external-ip
Advanced tools
Comparing version 0.2.4 to 1.0.0
#!/usr/bin/env node | ||
'use strict'; | ||
var program = require('commander'); | ||
var extIP = require('./extIP'); | ||
const program = require('commander'); | ||
const extIP = require('./extIP'); | ||
var collect = function (service, services) { | ||
const collect = (service, services) => { | ||
services.push(service); | ||
@@ -19,3 +19,3 @@ return services; | ||
program.on('--help', function () { | ||
program.on('--help', () => { | ||
console.log('This program prints the external IP of the machine.\n' + | ||
@@ -31,4 +31,4 @@ 'All arguments are optional.'); | ||
var generateConfig = function (cliConf) { | ||
var config = {}; | ||
const generateConfig = (cliConf) => { | ||
let config = {}; | ||
config.getIP = cliConf.parallel ? 'parallel' : 'sequential'; | ||
@@ -48,5 +48,5 @@ if (cliConf.timeout) { | ||
var getIP = extIP(generateConfig(program)); | ||
const getIP = extIP(generateConfig(program)); | ||
getIP(function (err, ip) { | ||
getIP((err, ip) =>{ | ||
if (err) { | ||
@@ -53,0 +53,0 @@ console.error(err); |
'use strict'; | ||
var requests = require('./requests'); | ||
var asyncLoop = require('evented-async-loop'); | ||
var utils = require('./utils'); | ||
const utils = require('./utils'); | ||
const defaultConfig = require('./defaultConfig'); | ||
module.exports = function (extConf) { | ||
extConf = extConf || {}; | ||
module.exports = (externalConfig = {}) => { | ||
var isValid = utils.validateConfig(extConf); | ||
const isValid = utils.validateConfig(externalConfig); | ||
@@ -16,56 +14,34 @@ if (isValid.errors.length) { | ||
// Check: https://github.com/mjhasbach/MOIRA | ||
var defConf = { | ||
getIP: 'sequential', // parallel | ||
replace: false, | ||
services: [ | ||
'http://ifconfig.co/x-real-ip', | ||
'http://icanhazip.com/', | ||
'http://ifconfig.io/ip', | ||
'http://ip.appspot.com/', | ||
'http://curlmyip.com/', | ||
'http://ident.me/', | ||
'http://whatismyip.akamai.com/', | ||
'http://tnx.nl/ip', | ||
'http://myip.dnsomatic.com/', | ||
'http://ipecho.net/plain', | ||
'http://diagnostic.opendns.com/myip' | ||
], | ||
timeout: 1000 | ||
}; | ||
const config = utils.mergeConfig(externalConfig, defaultConfig); | ||
const requests = config.services.map((url) => utils.requestFactory(config, url)); | ||
var config = utils.mergeConfig(extConf, defConf); | ||
const getIP = { | ||
sequential: (cb) => { | ||
let current = 0; | ||
let errors = []; | ||
var services = requests.setup(config).services; | ||
var loop = asyncLoop.create(services); | ||
var getIP = { | ||
sequential: function (cb) { | ||
loop.on('next', function (service, i, arr, errors) { | ||
service.getIP(function (err, ip) { | ||
if (err) { | ||
errors.push(service.url + ' : ' + err); | ||
loop.next(errors); | ||
} else { | ||
loop.done(null, ip); | ||
const loop = () => { | ||
requests[current]((error, ip) => { | ||
if (error) { | ||
errors.push(error); | ||
current += 1; | ||
if (current === requests.length) { | ||
return cb(errors, null); | ||
} | ||
return loop(); | ||
} | ||
return cb(null, ip); | ||
}); | ||
}) | ||
.on('done', function (errors, ip) { | ||
cb.apply(null, ip ? [null, ip] : [errors, null]); | ||
}) | ||
.start([]); | ||
}; | ||
loop(); | ||
}, | ||
parallel: function (cb) { | ||
var done = false; | ||
var errors = []; | ||
var requests; | ||
parallel: (cb) => { | ||
let done = false; | ||
let errors = []; | ||
let ongoingRequests; | ||
var abort = function (requests) { | ||
process.nextTick(function () { | ||
requests.forEach(function (request) { | ||
const abort = (requests) => { | ||
process.nextTick(() => { | ||
requests.forEach((request) => { | ||
request.abort(); | ||
@@ -77,3 +53,3 @@ }); | ||
var onResponse = function (err, ip) { | ||
const onResponse = function (err, ip) { | ||
@@ -86,10 +62,10 @@ if (done) { | ||
} | ||
if(ip) { | ||
if (ip) { | ||
done = true; | ||
abort(requests); //async | ||
abort(ongoingRequests); //async | ||
return cb(null, ip); | ||
} | ||
if (errors.length === services.length) { | ||
if (errors.length === requests.length) { | ||
done = true; | ||
abort(requests); //async | ||
abort(ongoingRequests); //async | ||
return cb(errors, null); | ||
@@ -99,5 +75,3 @@ } | ||
requests = services.map(function (service) { | ||
return service.getIP(onResponse); | ||
}); | ||
ongoingRequests = requests.map((service) => service(onResponse)); | ||
@@ -108,2 +82,2 @@ } | ||
return getIP[config.getIP]; | ||
}; | ||
}; |
111
lib/utils.js
'use strict'; | ||
var revalidator = require('revalidator'); | ||
const revalidator = require('revalidator'); | ||
const net = require('net'); | ||
const request = require('request'); | ||
/** | ||
* Taken from: https://github.com/parris/iz/blob/master/src/validators.js | ||
* Matches IPv4, IPv6 or hostname | ||
* @author Mikulas Dite http://stackoverflow.com/questions/9208814/validate-ipv4-ipv6-and-hostname | ||
* @param str | ||
* @return boolean | ||
*/ | ||
var isIP = function (str) { | ||
// How is this even possible??? | ||
var re = (/^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$|^(([a-zA-Z]|[a-zA-Z][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z]|[A-Za-z][A-Za-z0-9\-]*[A-Za-z0-9])$|^(?:(?:(?:(?:(?:(?:(?:[0-9a-fA-F]{1,4})):){6})(?:(?:(?:(?:(?:[0-9a-fA-F]{1,4})):(?:(?:[0-9a-fA-F]{1,4})))|(?:(?:(?:(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9]))\.){3}(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])))))))|(?:(?:::(?:(?:(?:[0-9a-fA-F]{1,4})):){5})(?:(?:(?:(?:(?:[0-9a-fA-F]{1,4})):(?:(?:[0-9a-fA-F]{1,4})))|(?:(?:(?:(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9]))\.){3}(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])))))))|(?:(?:(?:(?:(?:[0-9a-fA-F]{1,4})))?::(?:(?:(?:[0-9a-fA-F]{1,4})):){4})(?:(?:(?:(?:(?:[0-9a-fA-F]{1,4})):(?:(?:[0-9a-fA-F]{1,4})))|(?:(?:(?:(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9]))\.){3}(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])))))))|(?:(?:(?:(?:(?:(?:[0-9a-fA-F]{1,4})):){0,1}(?:(?:[0-9a-fA-F]{1,4})))?::(?:(?:(?:[0-9a-fA-F]{1,4})):){3})(?:(?:(?:(?:(?:[0-9a-fA-F]{1,4})):(?:(?:[0-9a-fA-F]{1,4})))|(?:(?:(?:(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9]))\.){3}(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])))))))|(?:(?:(?:(?:(?:(?:[0-9a-fA-F]{1,4})):){0,2}(?:(?:[0-9a-fA-F]{1,4})))?::(?:(?:(?:[0-9a-fA-F]{1,4})):){2})(?:(?:(?:(?:(?:[0-9a-fA-F]{1,4})):(?:(?:[0-9a-fA-F]{1,4})))|(?:(?:(?:(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9]))\.){3}(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])))))))|(?:(?:(?:(?:(?:(?:[0-9a-fA-F]{1,4})):){0,3}(?:(?:[0-9a-fA-F]{1,4})))?::(?:(?:[0-9a-fA-F]{1,4})):)(?:(?:(?:(?:(?:[0-9a-fA-F]{1,4})):(?:(?:[0-9a-fA-F]{1,4})))|(?:(?:(?:(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9]))\.){3}(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])))))))|(?:(?:(?:(?:(?:(?:[0-9a-fA-F]{1,4})):){0,4}(?:(?:[0-9a-fA-F]{1,4})))?::)(?:(?:(?:(?:(?:[0-9a-fA-F]{1,4})):(?:(?:[0-9a-fA-F]{1,4})))|(?:(?:(?:(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9]))\.){3}(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])))))))|(?:(?:(?:(?:(?:(?:[0-9a-fA-F]{1,4})):){0,5}(?:(?:[0-9a-fA-F]{1,4})))?::)(?:(?:[0-9a-fA-F]{1,4})))|(?:(?:(?:(?:(?:(?:[0-9a-fA-F]{1,4})):){0,6}(?:(?:[0-9a-fA-F]{1,4})))?::))))$/); | ||
return re.test(str); | ||
}; | ||
const isIP = (str) => net.isIP(str) !== 0; | ||
var validateConfig = function (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'] | ||
} | ||
} | ||
}); | ||
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'] | ||
} | ||
} | ||
}); | ||
}; | ||
var mergeConfig = function (extCfg, defCfg) { | ||
return { | ||
// Kill it with fire! | ||
services: extCfg.replace ? extCfg.services : extCfg.services && defCfg.services.concat(extCfg.services) || defCfg.services, | ||
timeout: extCfg.timeout || defCfg.timeout, | ||
getIP: extCfg.getIP || defCfg.getIP | ||
}; | ||
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 | ||
}; | ||
}; | ||
const requestFactory = (config, url) => { | ||
return (cb) => { | ||
return request.get({ | ||
url: url, | ||
timeout: config.timeout, | ||
headers: { | ||
'User-Agent': 'curl/' | ||
} | ||
}, (error, res, body = '') => { | ||
// if the body is null use an empty string | ||
if (error) { | ||
return cb(new Error(JSON.stringify({ code: error.code, url })), null); | ||
} | ||
// Parse and validate the body | ||
body = body.toString().replace('\n', ''); | ||
return cb.apply(null, isIP(body) ? [null, body] : [new Error(JSON.stringify({ code: 'invalid IP', url })), null]); | ||
}); | ||
}; | ||
}; | ||
module.exports = { | ||
isIP: isIP, | ||
validateConfig: validateConfig, | ||
mergeConfig: mergeConfig | ||
isIP, | ||
validateConfig, | ||
mergeConfig, | ||
requestFactory, | ||
}; |
{ | ||
"name": "external-ip", | ||
"version": "0.2.4", | ||
"version": "1.0.0", | ||
"description": "A node.js library to get your external ip from multiple services", | ||
@@ -38,10 +38,9 @@ "main": "index.js", | ||
"commander": "^2.9.0", | ||
"evented-async-loop": "^0.1.1", | ||
"request": "^2.40.0", | ||
"request": "^2.81.0", | ||
"revalidator": "^0.3.1" | ||
}, | ||
"devDependencies": { | ||
"chai": "^3.4.0", | ||
"mocha": "^2.3.3" | ||
"chai": "^4.0.2", | ||
"mocha": "^3.4.2" | ||
} | ||
} |
@@ -29,3 +29,3 @@ 'use strict'; | ||
replace: true, // true: replace the default services list, false: extend it, default: false | ||
services: ['http://ifconfig.co/x-real-ip', 'http://ifconfig.io/ip'], | ||
services: ['http://ident.me/', 'http://icanhazip.com/'], | ||
timeout: timeout, // set timeout per request, default: 500ms, | ||
@@ -32,0 +32,0 @@ getIP: 'parallel' |
@@ -11,3 +11,3 @@ 'use strict'; | ||
it('should be able to validate IPv4, IPv6 and hostnames', function () { | ||
it('should be able to validate IPv4 and IPv6', function () { | ||
@@ -18,5 +18,3 @@ expect(utils.isIP('192.168.1.1')).to.equal(true); | ||
expect(utils.isIP('FE80::0202:B3FF:FE1E:8329')).to.equal(true); | ||
expect(utils.isIP('batman.local')).to.equal(true); | ||
expect(utils.isIP(111111)).to.equal(false); | ||
@@ -23,0 +21,0 @@ expect(utils.isIP('192..1.1')).to.equal(false); |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
3
17
0
18901
357
1
- Removedevented-async-loop@^0.1.1
- Removedevented-async-loop@0.1.1(transitive)
Updatedrequest@^2.81.0