forked from ipfs-shipyard/ipfs-geoip
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This adds the formatted property which is used in ipfs/webui and ipfs/station. Ref ipfs/js-ipfsd-ctl#18
- Loading branch information
1 parent
9c960fd
commit 4ac800b
Showing
7 changed files
with
190 additions
and
84 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,39 +1,67 @@ | ||
# geoip lookup over ipfs | ||
# IPFS GeoIP | ||
|
||
Proof of concept | ||
> *Proof of concept:* Geoip lookup over ipfs | ||
# b-tree | ||
|
||
The utility geoip-gen reads csv files provided from GeoLite, and turns them into a 32-way branching b-tree, which is stored as ipfs json objects. | ||
## API | ||
|
||
# | ||
### `lookup(ipfs, ip, callback)` | ||
|
||
includes the generator, that can be called like this: | ||
Returns an object of the form | ||
|
||
```bash | ||
node geoip-gen.js path/GeoLite-Blocks.csv path/GeoLite-Location.csv | ||
```js | ||
{ | ||
"country_code": "US", | ||
"country_name": "United States", | ||
"region_code": "CA", | ||
"city": "Mountain View", | ||
"postal_code": "94040", | ||
"latitude": 37.3860, | ||
"longitude": -122.0838, | ||
"metro_code": "807", | ||
"area_code": "650", | ||
"planet": "Earth" | ||
} | ||
``` | ||
|
||
This takes quite a long time to import, but you only need to do it once globally to use the lookup feature. | ||
### `lookupPretty(ipfs, multiaddrs, callback)` | ||
|
||
and a lookup, for example, in the example directory | ||
Provides the same results as `lookup` with the addition of | ||
a `formatted` property that looks like this: `Mountain View, CA, United States, Earth`. | ||
|
||
``` | ||
node example/lookup.js 8.8.8.8 | ||
## b-tree | ||
|
||
The utility geoip-gen reads csv files provided from GeoLite, and turns them into a 32-way branching b-tree, which is stored as ipfs json objects. | ||
|
||
There is a generator included, that can be called like this: | ||
|
||
```bash | ||
$ node geoip-gen.js path/GeoLite-Blocks.csv path/GeoLite-Location.csv | ||
``` | ||
|
||
which will result in: | ||
This takes quite a long time to import, but you only need to do it once globally to use the lookup feature. | ||
|
||
```js | ||
{ | ||
"country_code": "US", | ||
## Example | ||
|
||
You can find an example of how to use this in [`example/lookup.js`](example/lookup.js), which you can use like this: | ||
|
||
```bash | ||
$ node example/lookup.js 8.8.8.8 | ||
Result: { | ||
"country_name": "United States", | ||
"country_code": "US", | ||
"region_code": "CA", | ||
"city": "Mountain View", | ||
"postal_code": "94040", | ||
"latitude": 37.3860, | ||
"latitude": 37.386, | ||
"longitude": -122.0838, | ||
"metro_code": "807", | ||
"area_code": "650" | ||
"area_code": "650", | ||
"planet": "Earth" | ||
} | ||
Pretty result: Mountain View, CA, United States, Earth | ||
``` | ||
|
||
## License | ||
|
||
[MIT](LICENSE) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,70 +1,11 @@ | ||
'use strict' | ||
var memoize = require('memoizee') | ||
|
||
var GEOIP_ROOT = 'QmQQ3BUpPjgYiTdhp4H9YWSCtoFXs8t91njhpvXNNLd3yB' | ||
var l = require('./lib/lookup') | ||
var lookupPretty = require('./lib/pretty') | ||
|
||
function aton4 (a) { | ||
a = a.split(/\./) | ||
return ((parseInt(a[0], 10) << 24) >>> 0) + ((parseInt(a[1], 10) << 16) >>> 0) + ((parseInt(a[2], 10) << 8) >>> 0) + (parseInt(a[3], 10) >>> 0) | ||
module.exports = { | ||
lookup: l.lookup, | ||
lookup_root: l.lookup_root, | ||
_lookup: l._lookup, | ||
lookupPretty: lookupPretty | ||
} | ||
|
||
function formatData (data) { | ||
var obj = {} | ||
|
||
if (data[0]) obj.country_name = data[0] | ||
if (data[1]) obj.country_code = data[1] | ||
if (data[2]) obj.region_code = data[2] | ||
if (data[3]) obj.city = data[3] | ||
if (data[4]) obj.postal_code = data[4] | ||
if (data[5]) obj.latitude = parseFloat(data[5]) | ||
if (data[6]) obj.longitude = parseFloat(data[6]) | ||
if (data[7]) obj.metro_code = data[7] | ||
if (data[8]) obj.area_code = data[8] | ||
|
||
return obj | ||
} | ||
|
||
var memoized_lookup | ||
|
||
function _lookup (ipfs, hash, lookfor, cb) { | ||
ipfs.object.get(hash, function (err, res) { | ||
if (err) { | ||
cb(err, null) | ||
} else { | ||
var obj = JSON.parse(res.Data) | ||
|
||
var child = 0 | ||
if (obj.type === 'Node') { | ||
while (obj.mins[child] && | ||
obj.mins[child] <= lookfor) { | ||
child++ | ||
} | ||
return memoized_lookup(ipfs, res.Links[child - 1].Hash, lookfor, cb) | ||
} else if (obj.type === 'Leaf') { | ||
while (obj.data[child] && | ||
obj.data[child].min <= lookfor) { | ||
child++ | ||
} | ||
if (obj.data[child - 1].data) { | ||
cb(null, formatData(obj.data[child - 1].data)) | ||
} else { | ||
cb('Unmapped range', null) | ||
} | ||
} | ||
} | ||
}) | ||
} | ||
|
||
memoized_lookup = memoize(_lookup, {async: true}) | ||
|
||
function lookup (ipfs, ip, cb) { | ||
memoized_lookup(ipfs, GEOIP_ROOT, aton4(ip), cb) | ||
} | ||
|
||
function lookup_root (ipfs, hash, ip, cb) { | ||
memoized_lookup(ipfs, hash, aton4(ip), cb) | ||
} | ||
|
||
module.exports = {lookup: lookup, | ||
lookup_root: lookup_root, | ||
_lookup: memoized_lookup} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
'use strict' | ||
|
||
module.exports = function aton4 (a) { | ||
a = a.split(/\./) | ||
|
||
return ((parseInt(a[0], 10) << 24) >>> 0) + | ||
((parseInt(a[1], 10) << 16) >>> 0) + | ||
((parseInt(a[2], 10) << 8) >>> 0) + | ||
(parseInt(a[3], 10) >>> 0) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
'use strict' | ||
|
||
// TODO(dignifiedquire): Adjust for more planets | ||
var PLANET = 'Earth' | ||
|
||
module.exports = function formatData (data) { | ||
var obj = {} | ||
|
||
if (data[0]) obj.country_name = data[0] | ||
if (data[1]) obj.country_code = data[1] | ||
if (data[2]) obj.region_code = data[2] | ||
if (data[3]) obj.city = data[3] | ||
if (data[4]) obj.postal_code = data[4] | ||
if (data[5]) obj.latitude = parseFloat(data[5]) | ||
if (data[6]) obj.longitude = parseFloat(data[6]) | ||
if (data[7]) obj.metro_code = data[7] | ||
if (data[8]) obj.area_code = data[8] | ||
|
||
obj.planet = PLANET | ||
|
||
return obj | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
'use strict' | ||
|
||
var memoize = require('memoizee') | ||
|
||
var formatData = require('./format') | ||
var aton4 = require('./aton4') | ||
|
||
var GEOIP_ROOT = 'QmQQ3BUpPjgYiTdhp4H9YWSCtoFXs8t91njhpvXNNLd3yB' | ||
|
||
var memoized_lookup | ||
|
||
function _lookup (ipfs, hash, lookfor, cb) { | ||
ipfs.object.get(hash, function (err, res) { | ||
if (err) { | ||
cb(err, null) | ||
} else { | ||
var obj = JSON.parse(res.Data) | ||
|
||
var child = 0 | ||
if (obj.type === 'Node') { | ||
while (obj.mins[child] && | ||
obj.mins[child] <= lookfor) { | ||
child++ | ||
} | ||
return memoized_lookup(ipfs, res.Links[child - 1].Hash, lookfor, cb) | ||
} else if (obj.type === 'Leaf') { | ||
while (obj.data[child] && | ||
obj.data[child].min <= lookfor) { | ||
child++ | ||
} | ||
|
||
if (obj.data[child - 1].data) { | ||
cb(null, formatData(obj.data[child - 1].data)) | ||
} else { | ||
cb('Unmapped range', null) | ||
} | ||
} | ||
} | ||
}) | ||
} | ||
|
||
memoized_lookup = memoize(_lookup, {async: true}) | ||
|
||
function lookup (ipfs, ip, cb) { | ||
memoized_lookup(ipfs, GEOIP_ROOT, aton4(ip), cb) | ||
} | ||
|
||
function lookup_root (ipfs, hash, ip, cb) { | ||
memoized_lookup(ipfs, hash, aton4(ip), cb) | ||
} | ||
|
||
module.exports = { | ||
lookup: lookup, | ||
lookup_root: lookup_root, | ||
_lookup: memoized_lookup | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
'use strict' | ||
|
||
var lookup = require('./lookup').lookup | ||
|
||
function isLocal (address) { | ||
var split = address.split('.') | ||
if (split[0] === '10') return true | ||
if (split[0] === '127') return true | ||
if (split[0] === '192' && split[1] === '168') return true | ||
if (split[0] === '172' && +split[1] >= 16 && +split[1] <= 31) return true | ||
return false | ||
} | ||
|
||
module.exports = function lookupPretty (ipfs, multiaddrs, cb) { | ||
if (multiaddrs.length === 0) return cb(null, null) | ||
if (typeof multiaddrs === 'string') multiaddrs = [multiaddrs] | ||
|
||
var address = multiaddrs[0].split('/')[2] | ||
if (isLocal(address)) return lookupPretty(ipfs, multiaddrs.slice(1), cb) | ||
|
||
lookup(ipfs, address, function (err, res) { | ||
if (err) return cb(err) | ||
|
||
if (!res.country_name && multiaddrs.length > 1) { | ||
return lookupPretty(ipfs, multiaddrs.slice(1), cb) | ||
} | ||
|
||
var location = [] | ||
|
||
if (res.planet) location.push(res.planet) | ||
if (res.country_name) location.unshift(res.country_name) | ||
if (res.region_code) location.unshift(res.region_code) | ||
if (res.city) location.unshift(res.city) | ||
|
||
res.formatted = location.join(', ') | ||
|
||
cb(null, res) | ||
}) | ||
} |