Join our webinar on Wednesday, June 26, at 1pm EDTHow Chia Mitigates Risk in the Crypto Industry.Register
Socket
Socket
Sign inDemoInstall

external-ip

Package Overview
Dependencies
51
Maintainers
1
Versions
30
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 1.3.1 to 2.0.0

lib/configSchema.json

67

lib/cli.js

@@ -7,5 +7,5 @@ #!/usr/bin/env node

const pkg = require('../package.json');
const defaultConfig = require('./defaultConfig');
const configSchema = require('./configSchema.json').properties;
const collect = (service, services) => {
const collect = (service, services = []) => {
services.push(service);

@@ -18,4 +18,12 @@ return services;

program.on('--help', () => {
console.log(`
program.usage('[options]')
.version(pkg.version)
.option('-R, --replace', 'replace internal services instead of extending them.')
.option('-s, --services <url>', 'service url, see examples, required if using -R', collect)
.option('-t, --timeout <ms>', 'set timeout per request', parseInt)
.option('-P, --parallel', 'set to parallel mode')
.option('-u, --userAgent <User-Agent>', `provide a User-Agent header, default: ${configSchema.userAgent.default}`, null, '')
.option('-v, --verbose', 'provide additional details')
.on('--help', () => {
console.log(`
This program prints the external IP of the machine.

@@ -25,47 +33,28 @@ All arguments are optional.\n

$ external-ip
$ external-ip -P -t 1500 -R -s ${defaultConfig.services[0]} -s ${defaultConfig.services[1]}\n
$ external-ip -P -t 1500 -R -s ${configSchema.services.default[0]} -s ${configSchema.services.default[1]}\n
Default services:
${defaultConfig.services.join('\n \t')}\n
${configSchema.services.default.join('\n \t')}\n
Documentation can be found at ${pkg.homepage}\n`);
});
program
.usage('[options]')
.version(pkg.version)
.option('-R, --replace', 'replace internal services instead of extending them.')
.option('-s, --services <url>', 'service url, see examples, required if using -R', collect, [])
.option('-t, --timeout <ms>', 'set timeout per request', parseInt)
.option('-P, --parallel', 'set to parallel mode')
.option('-u, --userAgent <User-Agent>', `provide a User-Agent header, default: ${defaultConfig.userAgent}`, null, '')
.option('-v, --verbose', 'provide additional details')
})
.parse(process.argv);
const generateConfig = (cliConf) => {
let config = {};
config.getIP = cliConf.parallel ? 'parallel' : 'sequential';
if (cliConf.timeout) {
config.timeout = cliConf.timeout;
}
if (cliConf.replace) {
config.replace = cliConf.replace;
}
if (cliConf.services.length) {
config.services = cliConf.services;
}
if (cliConf.userAgent) {
config.userAgent = cliConf.userAgent;
}
if (cliConf.verbose) {
config.verbose = cliConf.verbose;
}
return config;
return cliConf.options.reduce((acc, option) => {
const name = option.name();
if (cliConf[name]) {
acc[name] = cliConf[name];
}
return acc;
}, {
// Patch config for parallel option.
getIP: cliConf.parallel ? 'parallel' : undefined
});
};
const config = generateConfig(program);
const getIP = extIP(generateConfig(program));
getIP((err, ip) => {
extIP(config)((err, ip) => {
if (err) {
console.error(err);
console.error(err.message);
process.exit(1);

@@ -72,0 +61,0 @@ }

'use strict';
const utils = require('./utils');
const defaultConfig = require('./defaultConfig');
module.exports = (externalConfig = {}) => {
module.exports = (config = {}) => {
// validate the external configuration
const isValid = utils.validateConfig(externalConfig);
if (isValid.errors.length) {
console.error(isValid.errors);
// validate the external configuration and add the default values where needed
const configErrors = utils.prepareConfig(config);
if (configErrors) {
console.error(configErrors);
process.exit(1);
}
// merge the external configuration with the default
const config = utils.mergeConfig(externalConfig, defaultConfig);
// create a request instance for each service in the configuration

@@ -69,6 +64,4 @@ const requests = config.services.map((url) => utils.requestFactory(config, url));

done = true;
// Abort evey pending request
ongoingRequests.forEach((request) => {
request.abort();
});
// Abort every pending request
ongoingRequests.forEach((request) => request.abort());
return cb(null, ip);

@@ -75,0 +68,0 @@ }

'use strict';
const revalidator = require('revalidator');
const Ajv = require('ajv');
const ajv = new Ajv({
allErrors: true,
useDefaults: true
});
const configSchema = require('./configSchema.json');
const net = require('net');

@@ -28,56 +33,15 @@ const get = require('simple-get');

/**
* Validate the configuration object using jsonschema
* Prepare the configuration object.
* Validate using jsonschema and apply the required defaults
* @param {Object} config
* @return {Object} Errors in config if present
*/
const validateConfig = (config) => {
return revalidator.validate(config, {
properties: {
replace: {
description: 'true: replaces the default services, false: extends them',
type: 'boolean',
allowEmpty: false,
dependencies: 'services'
},
services: {
description: 'array of urls that return the ip in the document body',
type: 'array',
minItems: 1,
allowEmpty: false,
format: 'url'
},
timeout: {
description: 'timeout per request',
type: 'integer',
allowEmpty: false
},
getIP: {
description: 'sequential or parallel ip fetching',
type: 'string',
allowEmpty: false,
enum: ['parallel', 'sequential']
},
userAgent: {
description: 'Customize the User-Agent header',
type: 'string',
allowEmpty: false
}
}
});
};
const prepareConfig = (config) => {
// Merge or extend services acordingly
config.services = config.replace ? (config.services || []) : Array.isArray(config.services) ? config.services.concat(configSchema.properties.services.default) : configSchema.properties.services.default;
/**
* Merges the external configuration with the default
* @param {Object} externalConfig
* @param {Object} defaultConfig
* @return {Object}
*/
const mergeConfig = (externalConfig, defaultConfig) => {
return {
services: externalConfig.replace ? externalConfig.services : externalConfig.services && defaultConfig.services.concat(externalConfig.services) || defaultConfig.services,
timeout: externalConfig.timeout || defaultConfig.timeout,
getIP: externalConfig.getIP || defaultConfig.getIP,
userAgent: externalConfig.userAgent || defaultConfig.userAgent,
verbose: externalConfig.verbose || defaultConfig.verbose
};
const validate = ajv.compile(configSchema);
validate(config);
return validate.errors;
};

@@ -94,3 +58,6 @@

return (cb) => {
logger.info(`requesting IP from: ${url}`);
const startTime = Date.now();
return get.concat({

@@ -110,3 +77,3 @@ url: url,

if (isIP(body)) {
logger.info(`got valid IP from: ${url}`);
logger.info(`got valid IP from: ${url} in ${Date.now()- startTime}ms`);
return cb(null, body);

@@ -137,6 +104,5 @@ }

isIP,
validateConfig,
mergeConfig,
prepareConfig,
requestFactory,
concatErrors
};
{
"name": "external-ip",
"version": "1.3.1",
"version": "2.0.0",
"description": "A node.js library to get your external ip from multiple services",

@@ -37,10 +37,10 @@ "main": "index.js",

"dependencies": {
"commander": "^2.9.0",
"revalidator": "^0.3.1",
"simple-get": "^2.6.0"
"ajv": "^5.5.2",
"commander": "^2.15.0",
"simple-get": "^2.7.0"
},
"devDependencies": {
"chai": "^4.0.2",
"mocha": "^3.4.2"
"chai": "^4.1.2",
"mocha": "^3.5.3"
}
}
# external-ip
[![Build Status](https://travis-ci.org/J-Chaniotis/external-ip.svg?branch=master)](https://travis-ci.org/J-Chaniotis/external-ip)
[![Dependency Status](https://david-dm.org/j-Chaniotis/external-ip.svg)](https://david-dm.org/j-Chaniotis/external-ip)
[![npm version](https://badge.fury.io/js/external-ip.svg)](https://badge.fury.io/js/external-ip)

@@ -5,0 +6,0 @@ ![XKCD 865](http://imgs.xkcd.com/comics/nanobots.png)

@@ -16,4 +16,4 @@ 'use strict';

this.timeout(timeout);
let getIP = extIP();
getIP(function (err, ip) {
const getIP = extIP();
getIP((err, ip) =>{
expect(err).to.equal(null);

@@ -28,3 +28,3 @@ expect(utils.isIP(ip)).to.equal(true);

let getIP = extIP({
const getIP = extIP({
replace: true, // true: replace the default services list, false: extend it, default: false

@@ -36,3 +36,3 @@ services: ['http://ident.me/', 'http://icanhazip.com/'],

getIP(function (err, ip) {
getIP((err, ip) =>{
expect(err).to.equal(null);

@@ -39,0 +39,0 @@ expect(utils.isIP(ip)).to.equal(true);

@@ -7,2 +7,3 @@ 'use strict';

const expect = require('chai').expect;
const configSchema = require('../lib/configSchema.json');

@@ -32,3 +33,3 @@

timeout: 500,
gerIP: 'sequential'
getIP: 'sequential'
},

@@ -44,11 +45,52 @@ b: {

// An empty object is valid config
d: {}
d: {},
e: {
replace: true,
services: ['http://ifconfig.co/x-real-ip', 'http://ifconfig.io/ip']
},
f: {
replace: true,
services: ['http://ifconfig.co/x-real-ip']
},
g: {
services: ['http://ifconfig.co/x-real-ip']
},
};
expect(utils.validateConfig(config.a).valid).to.equal(true);
expect(utils.validateConfig(config.b).valid).to.equal(true);
expect(utils.validateConfig(config.c).valid).to.equal(true);
expect(utils.validateConfig(config.d).valid).to.equal(true);
const defaultLength = configSchema.properties.services.default.length;
expect(utils.prepareConfig(config.a)).to.equal(null);
expect(config.a.services.length).to.equal(defaultLength + 2);
expect(utils.prepareConfig(config.b)).to.equal(null);
expect(config.b.services.length).to.equal(defaultLength + 2);
expect(config.b.timeout).to.equal(500);
expect(utils.prepareConfig(config.c)).to.equal(null);
expect(config.c.services.length).to.equal(defaultLength);
expect(config.c.timeout).to.equal(500);
// Check all the default values
expect(utils.prepareConfig(config.d)).to.equal(null);
expect(config.d.services.length).to.equal(defaultLength);
expect(config.d.replace).to.equal(configSchema.properties.replace.default);
expect(config.d.timeout).to.equal(configSchema.properties.timeout.default);
expect(config.d.getIP).to.equal(configSchema.properties.getIP.default);
expect(config.d.userAgent).to.equal(configSchema.properties.userAgent.default);
expect(config.d.verbose).to.equal(configSchema.properties.verbose.default);
expect(utils.prepareConfig(config.e)).to.equal(null);
expect(config.e.services.length).to.equal(2);
expect(utils.prepareConfig(config.f)).to.equal(null);
expect(config.f.services.length).to.equal(1);
expect(utils.prepareConfig(config.g)).to.equal(null);
expect(config.g.services.length).to.equal(defaultLength + 1);
});
it('sould reject invalid config', function () {

@@ -71,46 +113,74 @@

expect(utils.validateConfig(config.a).errors.length).equal(4);
expect(utils.validateConfig(config.b).errors.length).equal(1);
expect(utils.validateConfig(config.c).errors.length).equal(1);
expect(utils.prepareConfig(config.a).length).equal(4);
expect(utils.prepareConfig(config.b).length).equal(1);
expect(utils.prepareConfig(config.c).length).equal(1);
});
it('should merge a valid configuration with default configuration', function () {
it('Should return an IP for every service entry in the default configuration', function (done) {
const defaultServices = configSchema.properties.services.default;
const config = {
default: {
replace: false,
services: ['http://ifconfig.co/x-real-ip', 'http://ifconfig.io/ip'],
timeout: 500,
getIP: 'sequential'
},
a: {},
b: {
services: ['http://ifconfig.co/x-real-ip', 'http://ifconfig.io/ip'],
timeout: 1000,
getIP: 'parallel'
},
c: {
replace: true,
services: ['http://ifconfig.co/x-real-ip']
}
timeout: 1000,
userAgent: 'curl/'
};
// set the test timeout taking every request into account
this.timeout(config.timeout * defaultServices.length);
// configure a request for every service
const requests = defaultServices.map((url) => utils.requestFactory(config, url));
let merged = utils.mergeConfig(config.a, config.default);
expect(merged).to.have.property('timeout', 500);
expect(merged).to.have.property('services').with.lengthOf(2);
expect(merged).to.have.property('getIP', 'sequential');
let completed = [];
// hit them and validate the results
requests.forEach((request) => {
request((error, ip) => {
expect(error).to.equal(null);
expect(utils.isIP(ip)).to.equal(true);
completed.push(ip);
// Every service has responded
if (completed.length === requests.length) {
merged = utils.mergeConfig(config.b, config.default);
expect(merged).to.have.property('timeout', 1000);
expect(merged).to.have.property('services').with.lengthOf(4);
expect(merged).to.have.property('getIP', 'parallel');
// When runing on travis IPs will not be the same because of the infrastructure
if(process.env.TRAVIS) {
return done();
}
// Check if every IP is the same
return (!!completed.reduce((a, b) => a === b ? a : NaN)) ? done() : done(new Error('IP mismatch'));
}
});
});
merged = utils.mergeConfig(config.c, config.default );
expect(merged).to.have.property('timeout', 500);
expect(merged).to.have.property('services').with.lengthOf(1);
});
it('should be able to fail as expected when an service cant be found', function (done) {
const config = {
timeout: 1000,
userAgent: 'curl/'
};
utils.requestFactory(config, 'http://i am doomed to fail cause i dont exist')((error, ip) => {
expect(ip).to.equal(null);
expect(error.message).to.contain('ENOTFOUND');
done();
});
});
it('should be able to fail as expected when an service wont return a valid IP', function (done) {
const config = {
timeout: 1000,
userAgent: 'curl/'
};
utils.requestFactory(config, 'http://www.google.com')((error, ip) => {
expect(ip).to.equal(null);
expect(error.message).to.contain('invalid IP');
done();
});
});
it('should be able to format multiple error messages', function () {
const error = utils.concatErrors([
new Error('Software failure.'),
new Error('Press left mouse button to continue'),
new Error('Guru Meditation '),
]);
expect(error.message).to.equal('Multiple errors: \n Software failure. \n Press left mouse button to continue \n Guru Meditation \n');
});
});

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc