[Pkg-javascript-commits] [node-proxy-addr] 01/02: Imported Upstream version 1.0.1
Leo Iannacone
l3on-guest at moszumanska.debian.org
Sat Jul 5 10:40:54 UTC 2014
This is an automated email from the git hooks/post-receive script.
l3on-guest pushed a commit to branch master
in repository node-proxy-addr.
commit d2fcf4a43dab1052be27646d2382388521bb95f9
Author: Leo Iannacone <l3on at ubuntu.com>
Date: Sat Jul 5 12:20:24 2014 +0200
Imported Upstream version 1.0.1
---
.npmignore | 4 +
.travis.yml | 11 ++
History.md | 27 +++
LICENSE | 22 +++
README.md | 124 +++++++++++++
benchmark/compiling.js | 49 ++++++
benchmark/index.js | 28 +++
benchmark/kind.js | 56 ++++++
benchmark/matching.js | 77 ++++++++
index.js | 353 +++++++++++++++++++++++++++++++++++++
package.json | 38 ++++
test/test.js | 465 +++++++++++++++++++++++++++++++++++++++++++++++++
12 files changed, 1254 insertions(+)
diff --git a/.npmignore b/.npmignore
new file mode 100644
index 0000000..85c82a5
--- /dev/null
+++ b/.npmignore
@@ -0,0 +1,4 @@
+benchmark/
+coverage/
+test/
+.travis.yml
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..1ff243c
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,11 @@
+language: node_js
+node_js:
+ - "0.8"
+ - "0.10"
+ - "0.11"
+matrix:
+ allow_failures:
+ - node_js: "0.11"
+ fast_finish: true
+script: "npm run-script test-travis"
+after_script: "npm install coveralls at 2.10.0 && cat ./coverage/lcov.info | coveralls"
diff --git a/History.md b/History.md
new file mode 100644
index 0000000..61a0d50
--- /dev/null
+++ b/History.md
@@ -0,0 +1,27 @@
+1.0.1 / 2014-06-03
+==================
+
+ * Fix links in npm package
+
+1.0.0 / 2014-05-08
+==================
+
+ * Add `trust` argument to determine proxy trust on
+ * Accepts custom function
+ * Accepts IPv4/IPv6 address(es)
+ * Accepts subnets
+ * Accepts pre-defined names
+ * Add optional `trust` argument to `proxyaddr.all` to
+ stop at first untrusted
+ * Add `proxyaddr.compile` to pre-compile `trust` function
+ to make subsequent calls faster
+
+0.0.1 / 2014-05-04
+==================
+
+ * Fix bad npm publish
+
+0.0.0 / 2014-05-04
+==================
+
+ * Initial release
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..b7dce6c
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,22 @@
+(The MIT License)
+
+Copyright (c) 2014 Douglas Christopher Wilson
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+'Software'), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..4fe57d3
--- /dev/null
+++ b/README.md
@@ -0,0 +1,124 @@
+# proxy-addr
+
+[![NPM version](https://badge.fury.io/js/proxy-addr.svg)](http://badge.fury.io/js/proxy-addr)
+[![Build Status](https://travis-ci.org/expressjs/proxy-addr.svg?branch=master)](https://travis-ci.org/expressjs/proxy-addr)
+[![Coverage Status](https://img.shields.io/coveralls/expressjs/proxy-addr.svg?branch=master)](https://coveralls.io/r/expressjs/proxy-addr)
+
+Determine address of proxied request
+
+## Install
+
+```sh
+$ npm install proxy-addr
+```
+
+## API
+
+```js
+var proxyaddr = require('proxy-addr')
+```
+
+### proxyaddr(req, trust)
+
+Return the address of the request, using the given `trust` parameter.
+
+The `trust` argument is a function that returns `true` if you trust
+the address, `false` if you don't. The closest untrusted address is
+returned.
+
+```js
+proxyaddr(req, function(addr){ return addr === '127.0.0.1' })
+proxyaddr(req, function(addr, i){ return i < 1 })
+```
+
+The `trust` arugment may also be a single IP address string or an
+array of trusted addresses, as plain IP addresses, CIDR-formatted
+strings, or IP/netmask strings.
+
+```js
+proxyaddr(req, '127.0.0.1')
+proxyaddr(req, ['127.0.0.0/8', '10.0.0.0/8'])
+proxyaddr(req, ['127.0.0.0/255.0.0.0', '192.168.0.0/255.255.0.0'])
+```
+
+This module also supports IPv6. Your IPv6 addresses will be normalized
+automatically (i.e. `fe80::00ed:1` equals `fe80:0:0:0:0:0:ed:1`).
+
+```js
+proxyaddr(req, '::1')
+proxyaddr(req, ['::1/128', 'fe80::/10'])
+proxyaddr(req, ['fe80::/ffc0::'])
+```
+
+This module will automatically work with IPv4-mapped IPv6 addresses
+as well to support node.js in IPv6-only mode. This means that you do
+not have to specify both `::ffff:a00:1` and `10.0.0.1`.
+
+As a convenience, this module also takes certain pre-defined names
+in addition to IP addresses, which expand into IP addresses:
+
+```js
+proxyaddr(req, 'loopback')
+proxyaddr(req, ['loopback', 'fc00:ac:1ab5:fff::1/64'])
+```
+
+ * `loopback`: IPv4 and IPv6 loopback addresses (like `::1` and
+ `127.0.0.1`).
+ * `linklocal`: IPv4 and IPv6 link-local addresses (like
+ `fe80::1:1:1:1` and `169.254.0.1`).
+ * `uniquelocal`: IPv4 private addresses and IPv6 unique-local
+ addresses (like `fc00:ac:1ab5:fff::1` and `192.168.0.1`).
+
+When `trust` is specified as a function, it will be called for each
+address to determine if it is a trusted address. The function is
+given two arguments: `addr` and `i`, where `addr` is a string of
+the address to check and `i` is a number that represents the distance
+from the socket address.
+
+### proxyaddr.all(req, [trust])
+
+Return all the addresses of the request, optionally stopping at the
+first untrusted. This array is ordered from closest to furthest
+(i.e. `arr[0] === req.connection.remoteAddress`).
+
+```js
+proxyaddr.all(req)
+```
+
+The optional `trust` argument takes the same arguments as `trust`
+does in `proxyaddr(req, trust)`.
+
+```js
+proxyaddr.all(req, 'loopback')
+```
+
+### proxyaddr.compile(val)
+
+Compiles argument `val` into a `trust` function. This function takes
+the same arguments as `trust` does in `proxyaddr(req, trust)` and
+returns a function suitable for `proxyaddr(req, trust)`.
+
+```js
+var trust = proxyaddr.compile('localhost')
+var addr = proxyaddr(req, trust)
+```
+
+This function is meant to be optimized for use against every request.
+It is recommend to compile a trust function up-front for the trusted
+configuration and pass that to `proxyaddr(req, trust)` for each request.
+
+## Testing
+
+```sh
+$ npm test
+```
+
+## Benchmarks
+
+```sh
+$ npm run-script bench
+```
+
+## License
+
+[MIT](LICENSE)
diff --git a/benchmark/compiling.js b/benchmark/compiling.js
new file mode 100644
index 0000000..11d78d7
--- /dev/null
+++ b/benchmark/compiling.js
@@ -0,0 +1,49 @@
+
+/**
+ * Globals for benchmark.js
+ */
+global.proxyaddr = require('..');
+global.createReq = createReq;
+
+/**
+ * Module dependencies.
+ */
+var benchmark = require('benchmark');
+var benchmarks = require('beautify-benchmark');
+
+var suite = new benchmark.Suite;
+
+suite.add({
+ 'name': 're-compiling',
+ 'minSamples': 100,
+ 'fn': 'proxyaddr(req, "loopback")',
+ 'setup': 'req = createReq("127.0.0.1", "10.0.0.1")'
+});
+
+suite.add({
+ 'name': 'pre-compiling',
+ 'minSamples': 100,
+ 'fn': 'proxyaddr(req, trust)',
+ 'setup': 'req = createReq("127.0.0.1", "10.0.0.1"); trust = proxyaddr.compile("loopback")'
+});
+
+suite.on('cycle', function onCycle(event) {
+ benchmarks.add(event.target);
+});
+
+suite.on('complete', function onComplete() {
+ benchmarks.log();
+});
+
+suite.run({'async': false});
+
+function createReq(socketAddr, forwardedFor) {
+ return {
+ connection: {
+ remoteAddress: socketAddr
+ },
+ headers: {
+ 'x-forwarded-for': (forwardedFor || '')
+ }
+ };
+}
diff --git a/benchmark/index.js b/benchmark/index.js
new file mode 100644
index 0000000..2fbd813
--- /dev/null
+++ b/benchmark/index.js
@@ -0,0 +1,28 @@
+var fs = require('fs');
+var path = require('path');
+var spawn = require('child_process').spawn;
+
+var exe = process.argv[0];
+var cwd = process.cwd();
+
+runScripts(fs.readdirSync(__dirname));
+
+function runScripts(fileNames) {
+ var fileName = fileNames.shift();
+
+ if (!fileName) return;
+ if (!/\.js$/i.test(fileName)) return runScripts(fileNames);
+ if (fileName.toLowerCase() === 'index.js') return runScripts(fileNames);
+
+ var fullPath = path.join(__dirname, fileName);
+
+ console.log('> %s %s', exe, path.relative(cwd, fullPath));
+
+ var proc = spawn(exe, [fullPath], {
+ 'stdio': 'inherit'
+ });
+
+ proc.on('exit', function () {
+ runScripts(fileNames);
+ });
+}
diff --git a/benchmark/kind.js b/benchmark/kind.js
new file mode 100644
index 0000000..d249878
--- /dev/null
+++ b/benchmark/kind.js
@@ -0,0 +1,56 @@
+
+/**
+ * Globals for benchmark.js
+ */
+global.proxyaddr = require('..');
+global.createReq = createReq;
+
+/**
+ * Module dependencies.
+ */
+var benchmark = require('benchmark');
+var benchmarks = require('beautify-benchmark');
+
+var suite = new benchmark.Suite;
+
+suite.add({
+ 'name': 'ipv4',
+ 'minSamples': 100,
+ 'fn': 'proxyaddr(req, trust)',
+ 'setup': 'req = createReq("127.0.0.1", "10.0.0.1"); trust = proxyaddr.compile("127.0.0.1")'
+});
+
+suite.add({
+ 'name': 'ipv4-mapped',
+ 'minSamples': 100,
+ 'fn': 'proxyaddr(req, trust)',
+ 'setup': 'req = createReq("::ffff:7f00:1", "10.0.0.1"); trust = proxyaddr.compile("127.0.0.1")'
+});
+
+suite.add({
+ 'name': 'ipv6',
+ 'minSamples': 100,
+ 'fn': 'proxyaddr(req, trust)',
+ 'setup': 'req = createReq("::1", "10.0.0.1"); trust = proxyaddr.compile("::1")'
+});
+
+suite.on('cycle', function onCycle(event) {
+ benchmarks.add(event.target);
+});
+
+suite.on('complete', function onComplete() {
+ benchmarks.log();
+});
+
+suite.run({'async': false});
+
+function createReq(socketAddr, forwardedFor) {
+ return {
+ connection: {
+ remoteAddress: socketAddr
+ },
+ headers: {
+ 'x-forwarded-for': (forwardedFor || '')
+ }
+ };
+}
diff --git a/benchmark/matching.js b/benchmark/matching.js
new file mode 100644
index 0000000..abcda04
--- /dev/null
+++ b/benchmark/matching.js
@@ -0,0 +1,77 @@
+
+/**
+ * Globals for benchmark.js
+ */
+global.proxyaddr = require('..');
+global.createReq = createReq;
+
+/**
+ * Module dependencies.
+ */
+var benchmark = require('benchmark');
+var benchmarks = require('beautify-benchmark');
+
+var suite = new benchmark.Suite;
+
+suite.add({
+ 'name': 'trust none',
+ 'minSamples': 100,
+ 'fn': 'proxyaddr(req, trust)',
+ 'setup': 'req = createReq("127.0.0.1", "10.0.0.1"); trust = proxyaddr.compile([])'
+});
+
+suite.add({
+ 'name': 'trust all',
+ 'minSamples': 100,
+ 'fn': 'proxyaddr(req, trust)',
+ 'setup': 'req = createReq("127.0.0.1", "10.0.0.1"); trust = function() {return true}'
+});
+
+suite.add({
+ 'name': 'trust single',
+ 'minSamples': 100,
+ 'fn': 'proxyaddr(req, trust)',
+ 'setup': 'req = createReq("127.0.0.1", "10.0.0.1"); trust = proxyaddr.compile("127.0.0.1")'
+});
+
+suite.add({
+ 'name': 'trust first',
+ 'minSamples': 100,
+ 'fn': 'proxyaddr(req, trust)',
+ 'setup': 'req = createReq("127.0.0.1", "10.0.0.1"); trust = function(a, i) {return i<1}'
+});
+
+suite.add({
+ 'name': 'trust subnet',
+ 'minSamples': 100,
+ 'fn': 'proxyaddr(req, trust)',
+ 'setup': 'req = createReq("127.0.0.1", "10.0.0.1"); trust = proxyaddr.compile("127.0.0.1/8")'
+});
+
+suite.add({
+ 'name': 'trust multiple',
+ 'minSamples': 100,
+ 'fn': 'proxyaddr(req, trust)',
+ 'setup': 'req = createReq("127.0.0.1", "10.0.0.1"); trust = proxyaddr.compile(["127.0.0.1", "10.0.0.1"])'
+});
+
+suite.on('cycle', function onCycle(event) {
+ benchmarks.add(event.target);
+});
+
+suite.on('complete', function onComplete() {
+ benchmarks.log();
+});
+
+suite.run({'async': false});
+
+function createReq(socketAddr, forwardedFor) {
+ return {
+ connection: {
+ remoteAddress: socketAddr
+ },
+ headers: {
+ 'x-forwarded-for': (forwardedFor || '')
+ }
+ };
+}
diff --git a/index.js b/index.js
new file mode 100644
index 0000000..75ee432
--- /dev/null
+++ b/index.js
@@ -0,0 +1,353 @@
+/*!
+ * proxy-addr
+ * Copyright(c) 2014 Douglas Christopher Wilson
+ * MIT Licensed
+ */
+
+/**
+ * Module exports.
+ */
+
+module.exports = proxyaddr;
+module.exports.all = alladdrs;
+module.exports.compile = compile;
+
+/**
+ * Module dependencies.
+ */
+
+var ipaddr = require('ipaddr.js');
+
+/**
+ * Variables.
+ */
+
+var digitre = /^[0-9]+$/;
+var isip = ipaddr.isValid;
+var parseip = ipaddr.parse;
+
+/**
+ * Pre-defined IP ranges.
+ */
+
+var ipranges = {
+ linklocal: ['169.254.0.0/16', 'fe80::/10'],
+ loopback: ['127.0.0.1/8', '::1/128'],
+ uniquelocal: ['10.0.0.0/8', '172.16.0.0/12', '192.168.0.0/16', 'fc00::/7']
+};
+
+/**
+ * Get all addresses in the request, optionally stopping
+ * at the first untrusted.
+ *
+ * @param {Object} request
+ * @param {Function|Array|String} [trust]
+ * @api public
+ */
+
+function alladdrs(req, trust) {
+ if (!req) {
+ throw new TypeError('req argument is required');
+ }
+
+ var proxyAddrs = (req.headers['x-forwarded-for'] || '')
+ .split(/ *, */)
+ .filter(Boolean)
+ .reverse();
+ var socketAddr = req.connection.remoteAddress;
+ var addrs = [socketAddr].concat(proxyAddrs);
+
+ if (!trust) {
+ // Return all addresses
+ return addrs;
+ }
+
+ if (typeof trust !== 'function') {
+ trust = compile(trust);
+ }
+
+ for (var i = 0; i < addrs.length - 1; i++) {
+ if (trust(addrs[i], i)) continue;
+
+ addrs.length = i + 1;
+ }
+
+ return addrs;
+}
+
+/**
+ * Compile argument into trust function.
+ *
+ * @param {Array|String} val
+ * @api private
+ */
+
+function compile(val) {
+ if (!val) {
+ throw new TypeError('argument is required');
+ }
+
+ var trust = typeof val === 'string'
+ ? [val]
+ : val;
+
+ if (!Array.isArray(trust)) {
+ throw new TypeError('unsupported trust argument');
+ }
+
+ for (var i = 0; i < trust.length; i++) {
+ val = trust[i];
+
+ if (!ipranges.hasOwnProperty(val)) {
+ continue;
+ }
+
+ // Splice in pre-defined range
+ val = ipranges[val];
+ trust.splice.apply(trust, [i, 1].concat(val));
+ i += val.length - 1;
+ }
+
+ return compileTrust(compileRangeSubnets(trust));
+}
+
+/**
+ * Compile `arr` elements into range subnets.
+ *
+ * @param {Array} arr
+ * @api private
+ */
+
+function compileRangeSubnets(arr) {
+ var rangeSubnets = new Array(arr.length);
+
+ for (var i = 0; i < arr.length; i++) {
+ rangeSubnets[i] = parseipNotation(arr[i]);
+ }
+
+ return rangeSubnets;
+}
+
+/**
+ * Compile range subnet array into trust function.
+ *
+ * @param {Array} rangeSubnets
+ * @api private
+ */
+
+function compileTrust(rangeSubnets) {
+ // Return optimized function based on length
+ var len = rangeSubnets.length;
+ return len === 0
+ ? trustNone
+ : len === 1
+ ? trustSingle(rangeSubnets[0])
+ : trustMulti(rangeSubnets);
+}
+
+/**
+ * Parse IP notation string into range subnet.
+ *
+ * @param {String} note
+ * @api private
+ */
+
+function parseipNotation(note) {
+ var ip;
+ var kind;
+ var max;
+ var pos = note.lastIndexOf('/');
+ var range;
+
+ ip = pos !== -1
+ ? note.substring(0, pos)
+ : note;
+
+ if (!isip(ip)) {
+ throw new TypeError('invalid IP address: ' + ip);
+ }
+
+ ip = parseip(ip);
+
+ kind = ip.kind();
+ max = kind === 'ipv4' ? 32
+ : kind === 'ipv6' ? 128
+ : 0;
+
+ range = pos !== -1
+ ? note.substring(pos + 1, note.length)
+ : max;
+
+ if (typeof range !== 'number') {
+ range = digitre.test(range)
+ ? parseInt(range, 10)
+ : isip(range)
+ ? parseNetmask(range)
+ : 0;
+ }
+
+ if (ip.kind() === 'ipv6' && ip.isIPv4MappedAddress()) {
+ // Store as IPv4
+ ip = ip.toIPv4Address();
+ range = range <= max
+ ? range - 96
+ : range;
+ }
+
+ if (range <= 0 || range > max) {
+ throw new TypeError('invalid range on address: ' + note);
+ }
+
+ return [ip, range];
+}
+
+/**
+ * Parse netmask string into CIDR range.
+ *
+ * @param {String} note
+ * @api private
+ */
+
+function parseNetmask(netmask) {
+ var ip = parseip(netmask);
+ var parts;
+ var size;
+
+ switch (ip.kind()) {
+ case 'ipv4':
+ parts = ip.octets;
+ size = 8;
+ break;
+ case 'ipv6':
+ parts = ip.parts;
+ size = 16;
+ break;
+ default:
+ throw new TypeError('unknown netmask');
+ }
+
+ var max = Math.pow(2, size) - 1;
+ var part;
+ var range = 0;
+
+ for (var i = 0; i < parts.length; i++) {
+ part = parts[i] & max;
+
+ if (part === max) {
+ range += size;
+ continue;
+ }
+
+ while (part) {
+ part = (part << 1) & max;
+ range += 1;
+ }
+
+ break;
+ }
+
+ return range;
+}
+
+/**
+ * Determine address of proxied request.
+ *
+ * @param {Object} request
+ * @param {Function|Array|String} trust
+ * @api public
+ */
+
+function proxyaddr(req, trust) {
+ if (!req) {
+ throw new TypeError('req argument is required');
+ }
+
+ if (!trust) {
+ throw new TypeError('trust argument is required');
+ }
+
+ var addrs = alladdrs(req, trust);
+ var addr = addrs[addrs.length - 1];
+
+ return addr;
+}
+
+/**
+ * Static trust function to trust nothing.
+ *
+ * @api private
+ */
+
+function trustNone() {
+ return false;
+}
+
+/**
+ * Compile trust function for multiple subnets.
+ *
+ * @param {Array} subnets
+ * @api private
+ */
+
+function trustMulti(subnets) {
+ return function trust(addr) {
+ if (!isip(addr)) return false;
+
+ var ip = parseip(addr);
+ var ipv4;
+ var kind = ip.kind();
+ var subnet;
+ var subnetip;
+ var subnetkind;
+ var trusted;
+
+ for (var i = 0; i < subnets.length; i++) {
+ subnet = subnets[i];
+ subnetip = subnet[0];
+ subnetkind = subnetip.kind();
+ subnetrange = subnet[1];
+ trusted = ip;
+
+ if (kind !== subnetkind) {
+ if (kind !== 'ipv6' || subnetkind !== 'ipv4' || !ip.isIPv4MappedAddress()) {
+ continue;
+ }
+
+ // Store addr as IPv4
+ ipv4 = ipv4 || ip.toIPv4Address();
+ trusted = ipv4;
+ }
+
+ if (trusted.match(subnetip, subnetrange)) return true;
+ }
+
+ return false;
+ };
+}
+
+/**
+ * Compile trust function for single subnet.
+ *
+ * @param {Object} subnet
+ * @api private
+ */
+
+function trustSingle(subnet) {
+ var subnetip = subnet[0];
+ var subnetkind = subnetip.kind();
+ var subnetisipv4 = subnetkind === 'ipv4';
+ var subnetrange = subnet[1];
+
+ return function trust(addr) {
+ if (!isip(addr)) return false;
+
+ var ip = parseip(addr);
+ var kind = ip.kind();
+
+ return kind === subnetkind
+ ? ip.match(subnetip, subnetrange)
+ : subnetisipv4 && kind === 'ipv6' && ip.isIPv4MappedAddress()
+ ? ip.toIPv4Address().match(subnetip, subnetrange)
+ : false;
+ };
+}
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..2f6bcaa
--- /dev/null
+++ b/package.json
@@ -0,0 +1,38 @@
+{
+ "name": "proxy-addr",
+ "description": "Determine address of proxied request",
+ "version": "1.0.1",
+ "author": "Douglas Christopher Wilson <doug at somethingdoug.com>",
+ "license": "MIT",
+ "keywords": [
+ "ip",
+ "proxy",
+ "x-forwarded-for"
+ ],
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/expressjs/proxy-addr.git"
+ },
+ "bugs": {
+ "url": "https://github.com/expressjs/proxy-addr/issues"
+ },
+ "dependencies": {
+ "ipaddr.js": "0.1.2"
+ },
+ "devDependencies": {
+ "benchmark": "1.0.0",
+ "beautify-benchmark": "0.2.4",
+ "istanbul": "0.2.10",
+ "mocha": "~1.20.0",
+ "should": "~4.0.0"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ },
+ "scripts": {
+ "bench": "node benchmark/index.js",
+ "test": "mocha --reporter dot test/",
+ "test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --reporter dot test/",
+ "test-travis": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --reporter spec test/"
+ }
+}
diff --git a/test/test.js b/test/test.js
new file mode 100644
index 0000000..1b05b90
--- /dev/null
+++ b/test/test.js
@@ -0,0 +1,465 @@
+
+var proxyaddr = require('..');
+var should = require('should');
+
+describe('proxyaddr(req, trust)', function () {
+ describe('arguments', function () {
+ describe('req', function () {
+ it('should be required', function () {
+ proxyaddr.bind().should.throw(/req.*required/);
+ });
+ });
+
+ describe('trust', function () {
+ it('should be required', function () {
+ var req = createReq('127.0.0.1');
+ proxyaddr.bind(null, req).should.throw(/trust.*required/);
+ });
+
+ it('should accept a function', function () {
+ var req = createReq('127.0.0.1');
+ proxyaddr.bind(null, req, all).should.not.throw();
+ });
+
+ it('should accept an array', function () {
+ var req = createReq('127.0.0.1');
+ proxyaddr.bind(null, req, []).should.not.throw();
+ });
+
+ it('should accept a string', function () {
+ var req = createReq('127.0.0.1');
+ proxyaddr.bind(null, req, '127.0.0.1').should.not.throw();
+ });
+
+ it('should reject a number', function () {
+ var req = createReq('127.0.0.1');
+ proxyaddr.bind(null, req, 42).should.throw(/unsupported trust argument/);
+ });
+
+ it('should accept IPv4', function () {
+ var req = createReq('127.0.0.1');
+ proxyaddr.bind(null, req, '127.0.0.1').should.not.throw();
+ });
+
+ it('should accept IPv6', function () {
+ var req = createReq('127.0.0.1');
+ proxyaddr.bind(null, req, '::1').should.not.throw();
+ });
+
+ it('should accept IPv4-style IPv6', function () {
+ var req = createReq('127.0.0.1');
+ proxyaddr.bind(null, req, '::ffff:127.0.0.1').should.not.throw();
+ });
+
+ it('should accept pre-defined names', function () {
+ var req = createReq('127.0.0.1');
+ proxyaddr.bind(null, req, 'loopback').should.not.throw();
+ });
+
+ it('should accept pre-defined names in array', function () {
+ var req = createReq('127.0.0.1');
+ proxyaddr.bind(null, req, ['loopback', '10.0.0.1']).should.not.throw();
+ });
+
+ it('should reject non-IP', function () {
+ var req = createReq('127.0.0.1');
+ proxyaddr.bind(null, req, 'blargh').should.throw(/invalid IP address/);
+ proxyaddr.bind(null, req, '10.0.300.1/16').should.throw(/invalid IP address/);
+ });
+
+ it('should reject bad CIDR', function () {
+ var req = createReq('127.0.0.1');
+ proxyaddr.bind(null, req, '10.0.0.1/6000').should.throw(/invalid range on address/);
+ proxyaddr.bind(null, req, '::1/6000').should.throw(/invalid range on address/);
+ proxyaddr.bind(null, req, '::ffff:a00:2/136').should.throw(/invalid range on address/);
+ proxyaddr.bind(null, req, '::ffff:a00:2/46').should.throw(/invalid range on address/);
+ });
+
+ it('should be invoked as trust(addr, i)', function () {
+ var log = [];
+ var req = createReq('127.0.0.1', {
+ 'x-forwarded-for': '192.168.0.1, 10.0.0.1'
+ });
+
+ proxyaddr(req, function (addr, i) {
+ return log.push(Array.prototype.slice.call(arguments));
+ });
+
+ log.should.eql([
+ ['127.0.0.1', 0],
+ ['10.0.0.1', 1]
+ ]);
+ });
+ });
+ });
+
+ describe('with all trusted', function () {
+ it('should return socket address with no headers', function () {
+ var req = createReq('127.0.0.1');
+ proxyaddr(req, all).should.equal('127.0.0.1');
+ });
+
+ it('should return header value', function () {
+ var req = createReq('127.0.0.1', {
+ 'x-forwarded-for': '10.0.0.1'
+ });
+ proxyaddr(req, all).should.equal('10.0.0.1');
+ });
+
+ it('should return furthest header value', function () {
+ var req = createReq('127.0.0.1', {
+ 'x-forwarded-for': '10.0.0.1, 10.0.0.2'
+ });
+ proxyaddr(req, all).should.equal('10.0.0.1');
+ });
+ });
+
+ describe('with none trusted', function () {
+ it('should return socket address with no headers', function () {
+ var req = createReq('127.0.0.1');
+ proxyaddr(req, none).should.equal('127.0.0.1');
+ });
+
+ it('should return socket address with headers', function () {
+ var req = createReq('127.0.0.1', {
+ 'x-forwarded-for': '10.0.0.1, 10.0.0.2'
+ });
+ proxyaddr(req, none).should.equal('127.0.0.1');
+ });
+ });
+
+ describe('with some trusted', function () {
+ it('should return socket address with no headers', function () {
+ var req = createReq('127.0.0.1');
+ proxyaddr(req, trust10x).should.equal('127.0.0.1');
+ });
+
+ it('should return socket address when not trusted', function () {
+ var req = createReq('127.0.0.1', {
+ 'x-forwarded-for': '10.0.0.1, 10.0.0.2'
+ });
+ proxyaddr(req, trust10x).should.equal('127.0.0.1');
+ });
+
+ it('should return header when socket trusted', function () {
+ var req = createReq('10.0.0.1', {
+ 'x-forwarded-for': '192.168.0.1'
+ });
+ proxyaddr(req, trust10x).should.equal('192.168.0.1');
+ });
+
+ it('should return first untrusted after trusted', function () {
+ var req = createReq('10.0.0.1', {
+ 'x-forwarded-for': '192.168.0.1, 10.0.0.2'
+ });
+ proxyaddr(req, trust10x).should.equal('192.168.0.1');
+ });
+
+ it('should not skip untrusted', function () {
+ var req = createReq('10.0.0.1', {
+ 'x-forwarded-for': '10.0.0.3, 192.168.0.1, 10.0.0.2'
+ });
+ proxyaddr(req, trust10x).should.equal('192.168.0.1');
+ });
+ });
+
+ describe('when given array', function () {
+ it('should accept literal IP addresses', function () {
+ var req = createReq('10.0.0.1', {
+ 'x-forwarded-for': '192.168.0.1, 10.0.0.2'
+ });
+ proxyaddr(req, ['10.0.0.1', '10.0.0.2']).should.equal('192.168.0.1');
+ });
+
+ it('should not trust non-IP addresses', function () {
+ var req = createReq('10.0.0.1', {
+ 'x-forwarded-for': '192.168.0.1, 10.0.0.2, localhost'
+ });
+ proxyaddr(req, ['10.0.0.1', '10.0.0.2']).should.equal('localhost');
+ });
+
+ it('should return socket address if none match', function () {
+ var req = createReq('10.0.0.1', {
+ 'x-forwarded-for': '192.168.0.1, 10.0.0.2'
+ });
+ proxyaddr(req, ['127.0.0.1', '192.168.0.100']).should.equal('10.0.0.1');
+ });
+
+ describe('when array empty', function () {
+ it('should return socket address ', function () {
+ var req = createReq('127.0.0.1');
+ proxyaddr(req, []).should.equal('127.0.0.1');
+ });
+
+ it('should return socket address with headers', function () {
+ var req = createReq('127.0.0.1', {
+ 'x-forwarded-for': '10.0.0.1, 10.0.0.2'
+ });
+ proxyaddr(req, []).should.equal('127.0.0.1');
+ });
+ });
+ });
+
+ describe('when given IPv4 addresses', function () {
+ it('should accept literal IP addresses', function () {
+ var req = createReq('10.0.0.1', {
+ 'x-forwarded-for': '192.168.0.1, 10.0.0.2'
+ });
+ proxyaddr(req, ['10.0.0.1', '10.0.0.2']).should.equal('192.168.0.1');
+ });
+
+ it('should accept CIDR notation', function () {
+ var req = createReq('10.0.0.1', {
+ 'x-forwarded-for': '192.168.0.1, 10.0.0.200'
+ });
+ proxyaddr(req, '10.0.0.2/26').should.equal('10.0.0.200');
+ });
+
+ it('should accept netmask notation', function () {
+ var req = createReq('10.0.0.1', {
+ 'x-forwarded-for': '192.168.0.1, 10.0.0.200'
+ });
+ proxyaddr(req, '10.0.0.2/255.255.255.192').should.equal('10.0.0.200');
+ });
+ });
+
+ describe('when given IPv6 addresses', function () {
+ it('should accept literal IP addresses', function () {
+ var req = createReq('fe80::1', {
+ 'x-forwarded-for': '2002:c000:203::1, fe80::2'
+ });
+ proxyaddr(req, ['fe80::1', 'fe80::2']).should.equal('2002:c000:203::1');
+ });
+
+ it('should accept CIDR notation', function () {
+ var req = createReq('fe80::1', {
+ 'x-forwarded-for': '2002:c000:203::1, fe80::ff00'
+ });
+ proxyaddr(req, 'fe80::/125').should.equal('fe80::ff00');
+ });
+
+ it('should accept netmask notation', function () {
+ var req = createReq('fe80::1', {
+ 'x-forwarded-for': '2002:c000:203::1, fe80::ff00'
+ });
+ proxyaddr(req, 'fe80::/ffff:ffff:ffff:ffff:ffff:ffff:ffff:fff8').should.equal('fe80::ff00');
+ });
+ });
+
+ describe('when IP versions mixed', function () {
+ it('should match respective versions', function () {
+ var req = createReq('::1', {
+ 'x-forwarded-for': '2002:c000:203::1'
+ });
+ proxyaddr(req, ['127.0.0.1', '::1']).should.equal('2002:c000:203::1');
+ });
+
+ it('should not match IPv4 to IPv6', function () {
+ var req = createReq('::1', {
+ 'x-forwarded-for': '2002:c000:203::1'
+ });
+ proxyaddr(req, '127.0.0.1').should.equal('::1');
+ });
+ });
+
+ describe('when IPv4-mapped IPv6 addresses', function () {
+ it('should match IPv4 trust to IPv6 request', function () {
+ var req = createReq('::ffff:a00:1', {
+ 'x-forwarded-for': '192.168.0.1, 10.0.0.2'
+ });
+ proxyaddr(req, ['10.0.0.1', '10.0.0.2']).should.equal('192.168.0.1');
+ });
+
+ it('should match IPv4 netmask trust to IPv6 request', function () {
+ var req = createReq('::ffff:a00:1', {
+ 'x-forwarded-for': '192.168.0.1, 10.0.0.2'
+ });
+ proxyaddr(req, ['10.0.0.1/16']).should.equal('192.168.0.1');
+ });
+
+ it('should match IPv6 trust to IPv4 request', function () {
+ var req = createReq('10.0.0.1', {
+ 'x-forwarded-for': '192.168.0.1, 10.0.0.2'
+ });
+ proxyaddr(req, ['::ffff:a00:1', '::ffff:a00:2']).should.equal('192.168.0.1');
+ });
+
+ it('should match CIDR notation for IPv4-mapped address', function () {
+ var req = createReq('10.0.0.1', {
+ 'x-forwarded-for': '192.168.0.1, 10.0.0.200'
+ });
+ proxyaddr(req, '::ffff:a00:2/122').should.equal('10.0.0.200');
+ });
+
+ it('should match subnet notation for IPv4-mapped address', function () {
+ var req = createReq('10.0.0.1', {
+ 'x-forwarded-for': '192.168.0.1, 10.0.0.200'
+ });
+ proxyaddr(req, '::ffff:a00:2/ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffc0').should.equal('10.0.0.200');
+ });
+ });
+
+ describe('when given pre-defined names', function () {
+ it('should accept single pre-defined name', function () {
+ var req = createReq('fe80::1', {
+ 'x-forwarded-for': '2002:c000:203::1, fe80::2'
+ });
+ proxyaddr(req, 'linklocal').should.equal('2002:c000:203::1');
+ });
+
+ it('should accept multiple pre-defined names', function () {
+ var req = createReq('::1', {
+ 'x-forwarded-for': '2002:c000:203::1, fe80::2'
+ });
+ proxyaddr(req, ['loopback', 'linklocal']).should.equal('2002:c000:203::1');
+ });
+ });
+
+ describe('when header contains non-ip addresses', function () {
+ it('should stop at first non-ip after trusted', function () {
+ var req = createReq('127.0.0.1', {
+ 'x-forwarded-for': 'myrouter, 127.0.0.1, proxy'
+ });
+ proxyaddr(req, '127.0.0.1').should.equal('proxy');
+ });
+
+ it('should provide all values to function', function () {
+ var log = [];
+ var req = createReq('127.0.0.1', {
+ 'x-forwarded-for': 'myrouter, 127.0.0.1, proxy'
+ });
+
+ proxyaddr(req, function (addr, i) {
+ return log.push(Array.prototype.slice.call(arguments));
+ });
+
+ log.should.eql([
+ ['127.0.0.1', 0],
+ ['proxy', 1],
+ ['127.0.0.1', 2]
+ ]);
+ });
+ });
+});
+
+describe('proxyaddr.all(req, [trust])', function () {
+ describe('arguments', function () {
+ describe('req', function () {
+ it('should be required', function () {
+ proxyaddr.all.bind().should.throw(/req.*required/);
+ });
+ });
+
+ describe('trust', function () {
+ it('should be optional', function () {
+ var req = createReq('127.0.0.1');
+ proxyaddr.all.bind(null, req).should.not.throw();
+ });
+ });
+ });
+
+ describe('with no headers', function () {
+ it('should return socket address', function () {
+ var req = createReq('127.0.0.1');
+ proxyaddr.all(req).should.eql(['127.0.0.1']);
+ });
+ });
+
+ describe('with x-forwarded-for header', function () {
+ it('should include x-forwarded-for', function () {
+ var req = createReq('127.0.0.1', {
+ 'x-forwarded-for': '10.0.0.1'
+ });
+ proxyaddr.all(req).should.eql(['127.0.0.1', '10.0.0.1']);
+ });
+
+ it('should include x-forwarded-for in correct order', function () {
+ var req = createReq('127.0.0.1', {
+ 'x-forwarded-for': '10.0.0.1, 10.0.0.2'
+ });
+ proxyaddr.all(req).should.eql(['127.0.0.1', '10.0.0.2', '10.0.0.1']);
+ });
+ });
+
+ describe('with trust argument', function () {
+ it('should stop at first untrusted', function () {
+ var req = createReq('127.0.0.1', {
+ 'x-forwarded-for': '10.0.0.1, 10.0.0.2'
+ });
+ proxyaddr.all(req, '127.0.0.1').should.eql(['127.0.0.1', '10.0.0.2']);
+ });
+
+ it('should be only socket address for no trust', function () {
+ var req = createReq('127.0.0.1', {
+ 'x-forwarded-for': '10.0.0.1, 10.0.0.2'
+ });
+ proxyaddr.all(req, []).should.eql(['127.0.0.1']);
+ });
+ });
+});
+
+describe('proxyaddr.compile(trust)', function () {
+ describe('arguments', function () {
+ describe('trust', function () {
+ it('should be required', function () {
+ proxyaddr.compile.bind(null).should.throw(/argument.*required/);
+ });
+
+ it('should accept an array', function () {
+ proxyaddr.compile([]).should.be.function;
+ });
+
+ it('should accept a string', function () {
+ proxyaddr.compile('127.0.0.1').should.be.function;
+ });
+
+ it('should reject a number', function () {
+ proxyaddr.compile.bind(null, 42).should.throw(/unsupported trust argument/);
+ });
+
+ it('should accept IPv4', function () {
+ proxyaddr.compile('127.0.0.1').should.be.function;
+ });
+
+ it('should accept IPv6', function () {
+ proxyaddr.compile('::1').should.be.function;
+ });
+
+ it('should accept IPv4-style IPv6', function () {
+ proxyaddr.compile('::ffff:127.0.0.1').should.be.function;
+ });
+
+ it('should accept pre-defined names', function () {
+ proxyaddr.compile('loopback').should.be.function;
+ });
+
+ it('should accept pre-defined names in array', function () {
+ proxyaddr.compile(['loopback', '10.0.0.1']).should.be.function;
+ });
+
+ it('should reject non-IP', function () {
+ proxyaddr.compile.bind(null, 'blargh').should.throw(/invalid IP address/);
+ });
+
+ it('should reject bad CIDR', function () {
+ proxyaddr.compile.bind(null, '10.0.0.1/6000').should.throw(/invalid range on address/);
+ proxyaddr.compile.bind(null, '::1/6000').should.throw(/invalid range on address/);
+ proxyaddr.compile.bind(null, '::ffff:a00:2/136').should.throw(/invalid range on address/);
+ proxyaddr.compile.bind(null, '::ffff:a00:2/46').should.throw(/invalid range on address/);
+ });
+ });
+ });
+});
+
+function createReq(socketAddr, headers) {
+ return {
+ connection: {
+ remoteAddress: socketAddr
+ },
+ headers: headers || {}
+ };
+}
+
+function all() { return true; }
+function none() { return false; }
+function trust10x(addr) { return /^10\./.test(addr); }
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-javascript/node-proxy-addr.git
More information about the Pkg-javascript-commits
mailing list