diff --git a/README.md b/README.md index 933b632..d34b079 100644 --- a/README.md +++ b/README.md @@ -44,6 +44,8 @@ export MAXMIND_LICENSE='your secret license' ``` npm run update-geo-data npm run update-asn-data +npm run update-isp-data +npm run update-connection-type-data ``` ### Periodic Updates for Geo/ASN data diff --git a/config/net.util.json.example b/config/net.util.json.example index 67546c4..487477e 100644 --- a/config/net.util.json.example +++ b/config/net.util.json.example @@ -1,3 +1,4 @@ { - "grcServices": [ "rest:util:net" ] + "grcServices": [ "rest:util:net" ], + "maxAccuracyRadius": 500 } diff --git a/test/integration.js b/test/integration.js index 96928c2..7cc14b8 100644 --- a/test/integration.js +++ b/test/integration.js @@ -249,4 +249,54 @@ describe('RPC integration', () => { } }) }).timeout(7000) + + it('geo-ip: retrieves ips with accuracy_radius < 500km has confidence score > 0', (done) => { + const query = { + action: 'getIpGeo', + args: ['2.125.160.216'] + } + + client.request(query, (err, data) => { + try { + if (err) throw err + + assert.strictEqual( + data[0], '2.125.160.216', 'result contains queried ip' + ) + + const res = data[1] + assert.ok(res.area < 500) + assert.ok(res.confidenceScore > 0 && res.confidenceScore < 1) + assert.strictEqual(res.country, 'GB') + done() + } catch (err) { + done(err) + } + }) + }).timeout(7000) + + it('geo-ip: retrieves ips with accuracy_radius > 500km has confidence score=0', (done) => { + const query2 = { + action: 'getIpGeo', + args: ['8.8.8.8'] + } + + client.request(query2, (err, data) => { + try { + if (err) throw err + + assert.strictEqual( + data[0], '8.8.8.8', 'result contains queried ip' + ) + + const res = data[1] + assert.ok(res.area > 500) + assert.strictEqual(res.confidenceScore, 0) + assert.strictEqual(res.country, 'US') + done() + } catch (err) { + done(err) + } + }) + }).timeout(7000) }) diff --git a/workers/api.net.util.wrk.js b/workers/api.net.util.wrk.js index 7324303..0fcc7ea 100644 --- a/workers/api.net.util.wrk.js +++ b/workers/api.net.util.wrk.js @@ -1,7 +1,7 @@ 'use strict' const path = require('path') - +const _ = require('lodash') // It looks like in the next release of geoip-lite // we can use GEODATADIR env instead of this gloabl env var, // but w/out it maxmind reads old data from in node_modules @@ -41,6 +41,10 @@ class WrkUtilNetApi extends WrkApi { ctx.geoIp = this.geoIp ctx.ispDb = this.ispDb ctx.connectionTypeDb = this.connectionTypeDb + ctx.conf = ctx.conf || {} + _.extend(ctx.conf, { + maxAccuracyRadius: this.conf.util.maxAccuracyRadius + }) break } diff --git a/workers/loc.api/net.util.js b/workers/loc.api/net.util.js index 6103487..f8a6aa1 100644 --- a/workers/loc.api/net.util.js +++ b/workers/loc.api/net.util.js @@ -12,7 +12,7 @@ class UtilNet extends Api { } getIpInfo (space, ip, cb) { - const geoData = this.ctx.geoIp.lookup(ip) + const geoData = this._getGeoIp(ip) const asnData = this.ctx.asnDb.get(ip) const ispData = this.ctx.ispDb.get(ip) const connectionTypeData = this.ctx.connectionTypeDb.get(ip) @@ -46,7 +46,7 @@ class UtilNet extends Api { } getIpGeo (space, ip, cb) { - const res = this.ctx.geoIp.lookup(ip) + const res = this._getGeoIp(ip) cb(null, [ip, res]) } @@ -74,7 +74,7 @@ class UtilNet extends Api { } const res = ips.map((ip) => { - return [ip, this.ctx.geoIp.lookup(ip)] + return [ip, this._getGeoIp(ip)] }) cb(null, res) @@ -87,6 +87,26 @@ class UtilNet extends Api { cb(null, [ip, data]) }) } + + _getGeoIp (ip) { + const res = this.ctx.geoIp.lookup(ip) + const { maxAccuracyRadius } = this.ctx.conf + + const confidenceScore = this._calculateConfidenceScore(res, maxAccuracyRadius) + return { ...res, confidenceScore } + } + + _calculateConfidenceScore (geo, maxAccuracyRadius) { + if (!geo || geo.area == null) { + return 0 + } + const accuracyRadius = geo.area + + // Simple linear mapping of radius to confidence score + const confidence = Math.max(0, Math.min(1, 1 - (accuracyRadius / maxAccuracyRadius))) + + return confidence + } } module.exports = UtilNet