pixl-server-web 1.3.12 → 1.3.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -50,6 +50,7 @@ This module is a component for use in [pixl-server](https://www.github.com/jhuck
50
50
  * [http_req_max_dump_enabled](#http_req_max_dump_enabled)
51
51
  * [http_req_max_dump_dir](#http_req_max_dump_dir)
52
52
  * [http_req_max_dump_debounce](#http_req_max_dump_debounce)
53
+ * [http_public_ip_offset](#http_public_ip_offset)
53
54
  * [https](#https)
54
55
  * [https_port](#https_port)
55
56
  * [https_cert_file](#https_cert_file)
@@ -529,6 +530,19 @@ When the [Request Max Dump](#request-max-dump) system is enabled, the `http_req_
529
530
 
530
531
  When the [Request Max Dump](#request-max-dump) system is enabled, the `http_req_max_dump_debounce` property sets how many seconds should elapse between dumps, as to not overwhelm the filesystem.
531
532
 
533
+ ## http_public_ip_offset
534
+
535
+ This controls how [args.ip](#argsip) is chosen from the list of IP addresses in [args.ips](#argsips) for each incoming request. By default, the client IP is chosen by scanning the list from left to right, and selecting the first non-private IP. However, [modern wisdom](https://adam-p.ca/blog/2022/03/x-forwarded-for/) suggests that alternate selection logic may be more desirable to find the true public IP.
536
+
537
+ By setting `http_public_ip_offset` to an integer value, you can select *exactly* which IP to select from the list. Use negative numbers to select IP address from the *end* (right side) of the list. Here are the recommended values:
538
+
539
+ | Offset | Description |
540
+ |--------|-------------|
541
+ | `0` | The default value. Allow the server to select the public IP automatically. |
542
+ | `-1` | Always select the *last* IP in the list (i.e. the TCP socket IP). Use this mode if your server is connected to the internet directly. |
543
+ | `-2` | Always select the *second-to-last* IP in the list. Use this mode if you have a single proxy device in front of your server (e.g. a load balancer). |
544
+ | `-3` | Always select the *third-to-last* IP in the list. Use this mode if you have two proxy devices in front of your server (e.g. a load balancer and CDN / cache). |
545
+
532
546
  ## https
533
547
 
534
548
  This boolean allows you to enable HTTPS (SSL) support in the web server. It defaults to `false`. Note that you must also set `https_port`, and possibly `https_cert_file` and `https_key_file` for this to work.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pixl-server-web",
3
- "version": "1.3.12",
3
+ "version": "1.3.13",
4
4
  "description": "A web server component for the pixl-server framework.",
5
5
  "author": "Joseph Huckaby <jhuckaby@gmail.com>",
6
6
  "homepage": "https://github.com/jhuckaby/pixl-server-web",
package/test/test.js CHANGED
@@ -1339,6 +1339,71 @@ module.exports = {
1339
1339
  );
1340
1340
  },
1341
1341
 
1342
+ // http_public_ip_offset
1343
+ function testForwardedForOffsetNeg1(test) {
1344
+ var self = this;
1345
+ var web = this.web_server;
1346
+ web.config.set('http_public_ip_offset', -1);
1347
+
1348
+ request.json( 'http://127.0.0.1:3020/json', false,
1349
+ {
1350
+ headers: {
1351
+ "X-Forwarded-For": "1.2.3.4, 2.3.4.5, 3.4.5.6"
1352
+ }
1353
+ },
1354
+ function(err, resp, data, perf) {
1355
+ test.ok( !err, "No error from PixlRequest: " + err );
1356
+ test.ok( !!resp, "Got resp from PixlRequest" );
1357
+ test.ok( resp.statusCode == 200, "Got 200 response: " + resp.statusCode );
1358
+ test.ok( data.ip === "127.0.0.1", "Correct offset public IP in response: " + data.ip );
1359
+ web.config.set('http_public_ip_offset', 0); // reset
1360
+ test.done();
1361
+ }
1362
+ );
1363
+ },
1364
+ function testForwardedForOffsetNeg2(test) {
1365
+ var self = this;
1366
+ var web = this.web_server;
1367
+ web.config.set('http_public_ip_offset', -2);
1368
+
1369
+ request.json( 'http://127.0.0.1:3020/json', false,
1370
+ {
1371
+ headers: {
1372
+ "X-Forwarded-For": "1.2.3.4, 2.3.4.5, 3.4.5.6"
1373
+ }
1374
+ },
1375
+ function(err, resp, data, perf) {
1376
+ test.ok( !err, "No error from PixlRequest: " + err );
1377
+ test.ok( !!resp, "Got resp from PixlRequest" );
1378
+ test.ok( resp.statusCode == 200, "Got 200 response: " + resp.statusCode );
1379
+ test.ok( data.ip === "3.4.5.6", "Correct offset public IP in response: " + data.ip );
1380
+ web.config.set('http_public_ip_offset', 0); // reset
1381
+ test.done();
1382
+ }
1383
+ );
1384
+ },
1385
+ function testForwardedForOffsetNeg3(test) {
1386
+ var self = this;
1387
+ var web = this.web_server;
1388
+ web.config.set('http_public_ip_offset', -3);
1389
+
1390
+ request.json( 'http://127.0.0.1:3020/json', false,
1391
+ {
1392
+ headers: {
1393
+ "X-Forwarded-For": "1.2.3.4, 2.3.4.5, 3.4.5.6"
1394
+ }
1395
+ },
1396
+ function(err, resp, data, perf) {
1397
+ test.ok( !err, "No error from PixlRequest: " + err );
1398
+ test.ok( !!resp, "Got resp from PixlRequest" );
1399
+ test.ok( resp.statusCode == 200, "Got 200 response: " + resp.statusCode );
1400
+ test.ok( data.ip === "2.3.4.5", "Correct offset public IP in response: " + data.ip );
1401
+ web.config.set('http_public_ip_offset', 0); // reset
1402
+ test.done();
1403
+ }
1404
+ );
1405
+ },
1406
+
1342
1407
  // acl block
1343
1408
  function testACL(test) {
1344
1409
  request.get( 'http://127.0.0.1:3020/server-status', // ACL'ed endpoint
package/web_server.js CHANGED
@@ -366,13 +366,22 @@ class WebServer extends Component {
366
366
 
367
367
  getPublicIP(ips) {
368
368
  // filter out garbage that doesn't resemble ips
369
+ var public_ip_offset = this.config.get('http_public_ip_offset') || 0;
370
+
369
371
  var real_ips = ips.filter( function(ip) {
370
372
  return ip.match( /^([\d\.]+|[a-f0-9:]+)$/ );
371
373
  } );
372
374
 
373
- // determine first public IP from list of IPs
374
- for (var idx = 0, len = real_ips.length; idx < len; idx++) {
375
- if (!this.aclPrivateRanges.check(real_ips[idx])) return real_ips[idx];
375
+ if (public_ip_offset) {
376
+ // locate public IP using custom offset (usually negative, from end of list)
377
+ var temp = real_ips.slice( public_ip_offset, public_ip_offset + 1 || real_ips.length );
378
+ if (temp[0]) return temp[0];
379
+ }
380
+ else {
381
+ // determine first public IP from list of IPs
382
+ for (var idx = 0, len = real_ips.length; idx < len; idx++) {
383
+ if (!this.aclPrivateRanges.check(real_ips[idx])) return real_ips[idx];
384
+ }
376
385
  }
377
386
 
378
387
  // default to first ip