maxmind-db-reader
Advanced tools
Comparing version 0.0.2 to 0.2.0
35
index.js
@@ -6,12 +6,31 @@ 'use strict'; | ||
MaxmindDBReader = module.exports = function (database) { | ||
if (database === undefined) { | ||
throw new Error('MaxmindDBReader: No Database given'); | ||
} | ||
MaxmindDBReader = module.exports = function () { | ||
// allow creation without 'new' keyword | ||
if (!(this instanceof MaxmindDBReader)) | ||
return new MaxmindDBReader(); | ||
}; | ||
this.reader = new Reader(database); | ||
MaxmindDBReader.open = function(database,callback){ | ||
Reader.open(database,function(err, reader){ | ||
if(err){ | ||
return callback(err); | ||
} | ||
var mmdbreader = MaxmindDBReader(); | ||
mmdbreader.reader = reader; | ||
callback(null,mmdbreader); | ||
}); | ||
} | ||
MaxmindDBReader.openSync = function(database){ | ||
var mmdbreader = MaxmindDBReader(); | ||
mmdbreader.reader = Reader.openSync(database); | ||
return mmdbreader | ||
} | ||
MaxmindDBReader.prototype.getGeoData = function getGeoData(ipAddress,callback) { | ||
this.reader.get(ipAddress,callback); | ||
}; | ||
MaxmindDBReader.prototype.getGeoData = function getGeoData(ipAddress) { | ||
return this.reader.get(ipAddress); | ||
MaxmindDBReader.prototype.getGeoDataSync = function getGeoDataSync(ipAddress) { | ||
return this.reader.getSync(ipAddress); | ||
}; | ||
@@ -21,2 +40,2 @@ | ||
return this.reader.getMetadata(); | ||
}; | ||
}; |
@@ -30,4 +30,5 @@ 'use strict'; | ||
Decoder.prototype.decode = function decode(offset) { | ||
Decoder.prototype.decode = function decode(offset,callback,nexttick) { | ||
var tmp, | ||
that = this, | ||
ctrlByte = this.fileStream[offset++], | ||
@@ -39,3 +40,7 @@ type = this.types[ctrlByte >> 5] | ||
tmp = this.decodePointer(ctrlByte, offset); | ||
return [this.decode(tmp[0])[0], tmp[1]]; | ||
this.decode(tmp[0],function(err,data){ | ||
if(err) return callback(err); | ||
callback(null, [data[0], tmp[1]]); | ||
},nexttick); | ||
return; | ||
} | ||
@@ -47,2 +52,67 @@ | ||
if (tmp < 8) { | ||
return callback(new Error('MaxmindDBReader: Invalid Extended Type at offset:' + offset)); | ||
} | ||
type = this.types[tmp]; | ||
offset++; | ||
} | ||
tmp = this.sizeFromCtrlByte(ctrlByte, offset); | ||
if(nexttick === false) | ||
this.decodeByType(type, tmp[1], tmp[0],callback); | ||
else | ||
process.nextTick(function(){ | ||
that.decodeByType(type, tmp[1], tmp[0],callback); | ||
}); | ||
}; | ||
Decoder.prototype.decodeByType = function decodeByType(type, offset, size,callback) { | ||
var newOffset = offset + size, | ||
bytes = this.read(offset, size) | ||
; | ||
switch (type) { | ||
case 'map': | ||
return this.decodeMap(size, offset,callback); | ||
case 'array': | ||
return this.decodeArray(size, offset,callback); | ||
case 'boolean': | ||
return callback(null,[this.decodeBoolean(size), offset]); | ||
case 'utf8_string': | ||
return callback(null,[this.decodeString(bytes), newOffset]); | ||
case 'double': | ||
return callback(null,[this.decodeDouble(bytes), newOffset]); | ||
case 'float': | ||
return callback(null,[this.decodeFloat(bytes), newOffset]); | ||
case 'bytes': | ||
return callback(null,[bytes, newOffset]); | ||
case 'uint16': | ||
return callback(null,[this.decodeUint16(bytes), newOffset]); | ||
case 'uint32': | ||
return callback(null,[this.decodeUint32(bytes), newOffset]); | ||
case 'int32': | ||
return callback(null,[this.decodeInt32(bytes), newOffset]); | ||
case 'uint64': | ||
return callback(null,[this.decodeUint64(bytes), newOffset]); | ||
case 'uint128': | ||
return callback(null,[this.decodeUint128(bytes), newOffset]); | ||
} | ||
callback(new Error("MaxmindDBReader: Unknown or unexpected type: " + type + ' at offset:' + offset)); | ||
}; | ||
Decoder.prototype.decodeSync = function decodeSync(offset) { | ||
var tmp, | ||
ctrlByte = this.fileStream[offset++], | ||
type = this.types[ctrlByte >> 5] | ||
; | ||
if (type === 'pointer') { | ||
tmp = this.decodePointer(ctrlByte, offset); | ||
return [this.decodeSync(tmp[0])[0], tmp[1]]; | ||
} | ||
if (type === 'extended') { | ||
tmp = this.fileStream[offset] + 7; | ||
if (tmp < 8) { | ||
throw new Error('MaxmindDBReader: Invalid Extended Type at offset:' + offset); | ||
@@ -57,6 +127,6 @@ } | ||
return this.decodeByType(type, tmp[1], tmp[0]); | ||
return this.decodeByTypeSync(type, tmp[1], tmp[0]); | ||
}; | ||
Decoder.prototype.decodeByType = function decodeByType(type, offset, size) { | ||
Decoder.prototype.decodeByTypeSync = function decodeByTypeSync(type, offset, size) { | ||
var newOffset = offset + size, | ||
@@ -67,4 +137,4 @@ bytes = this.read(offset, size) | ||
switch (type) { | ||
case 'map': return this.decodeMap(size, offset); | ||
case 'array': return this.decodeArray(size, offset); | ||
case 'map': return this.decodeMapSync(size, offset); | ||
case 'array': return this.decodeArraySync(size, offset); | ||
case 'boolean': return [this.decodeBoolean(size), offset]; | ||
@@ -136,3 +206,26 @@ case 'utf8_string': return [this.decodeString(bytes), newOffset]; | ||
Decoder.prototype.decodeArray = function decodeArray(size, offset) { | ||
Decoder.prototype.decodeArray = function decodeArray(size, offset,callback) { | ||
var that = this; | ||
process.nextTick(function(){ | ||
var tmp, | ||
i = 1, | ||
array = [], | ||
cb = function(err,tmp){ | ||
if(err){ | ||
return callback(err); | ||
} | ||
offset = tmp[1]; | ||
array.push(tmp[0]); | ||
if(i++ < size){ | ||
that.decode(offset,cb,i%20===0); | ||
}else{ | ||
callback(null, [array,offset]); | ||
} | ||
}; | ||
if(size === 0) callback(null,[[],offset]); | ||
that.decode(offset,cb,false); | ||
}); | ||
}; | ||
Decoder.prototype.decodeArraySync = function decodeArraySync(size, offset) { | ||
var tmp, | ||
@@ -144,3 +237,3 @@ i = 0, | ||
for(i; i < size; i++) { | ||
tmp = this.decode(offset); | ||
tmp = this.decodeSync(offset); | ||
offset = tmp[1]; | ||
@@ -165,3 +258,30 @@ array.push(tmp[0]); | ||
Decoder.prototype.decodeMap = function decodeMap(size, offset) { | ||
Decoder.prototype.decodeMap = function decodeMap(size, offset,callback) { | ||
var that = this; | ||
process.nextTick(function(){ | ||
var tmp, key, | ||
map = {}, | ||
i = 1, | ||
cb = function(err,tmp){ | ||
if(err){ | ||
return callback(err); | ||
} | ||
map[key] = tmp[0]; | ||
offset = tmp[1]; | ||
if(i++ < size){ | ||
tmp = that.decodeSync(offset); | ||
key = tmp[0].toString(); | ||
that.decode(tmp[1],cb,i%20===0); | ||
}else{ | ||
callback(null, [map,offset]); | ||
} | ||
}; | ||
if(size === 0) return callback(null,[{},offset]); | ||
tmp = that.decodeSync(offset); | ||
key = tmp[0].toString(); | ||
that.decode(tmp[1],cb,false); | ||
}); | ||
}; | ||
Decoder.prototype.decodeMapSync = function decodeMapSync(size, offset) { | ||
var tmp, key, | ||
@@ -173,5 +293,5 @@ map = {}, | ||
for (i; i < size; i++) { | ||
tmp = this.decode(offset); | ||
tmp = this.decodeSync(offset); | ||
key = tmp[0].toString(); | ||
tmp = this.decode(tmp[1]); | ||
tmp = this.decodeSync(tmp[1]); | ||
offset = tmp[1]; | ||
@@ -178,0 +298,0 @@ map[key] = tmp[0]; |
@@ -8,3 +8,3 @@ 'use strict'; | ||
this.binaryFormatMinorVersion = metadata.binary_format_minor_version; | ||
this.buildEpoch = metadata.build_epoch; | ||
this.buildEpoch = new Date(metadata.build_epoch*1000); | ||
this.databaseType = metadata.database_type; | ||
@@ -11,0 +11,0 @@ this.languages = metadata.languages; |
@@ -8,15 +8,38 @@ 'use strict'; | ||
Decoder = require('./Decoder.js'), | ||
IPParser = require('./IPParser.js'), | ||
Reader; | ||
Reader = module.exports = function (database) { | ||
Reader = module.exports = function () {}; | ||
Reader.open = function(database, callback){ | ||
var reader = new Reader(); | ||
var start, metadataDecoder, metadataArray; | ||
fs.readFile(database,function(err, data){ | ||
if(err){ | ||
callback && callback(err); | ||
return; | ||
} | ||
reader.fileHandle =data; | ||
start = reader.findMetadataStart(reader.fileHandle); | ||
metadataDecoder = new Decoder(reader.fileHandle, 0); | ||
metadataDecoder.decode(start,function(err,metadata){ | ||
reader.metadata = new Metadata(metadata[0]); | ||
reader.decoder = new Decoder(reader.fileHandle, reader.metadata.getSearchTreeSize() + DATA_SECTION_SEPARATOR_SIZE); | ||
callback && callback(null,reader); | ||
}); | ||
}); | ||
} | ||
this.fileHandle = fs.readFileSync(database); | ||
Reader.openSync = function (database) { | ||
var reader = new Reader(); | ||
var start, metadataDecoder, metadataArray; | ||
start = this.findMetadataStart(this.fileHandle); | ||
metadataDecoder = new Decoder(this.fileHandle, 0); | ||
metadataArray = metadataDecoder.decode(start); | ||
reader.fileHandle = fs.readFileSync(database); | ||
this.metadata = new Metadata(metadataArray[0]); | ||
this.decoder = new Decoder(this.fileHandle, this.metadata.getSearchTreeSize() + DATA_SECTION_SEPARATOR_SIZE); | ||
start = reader.findMetadataStart(reader.fileHandle); | ||
metadataDecoder = new Decoder(reader.fileHandle, 0); | ||
metadataArray = metadataDecoder.decodeSync(start); | ||
reader.metadata = new Metadata(metadataArray[0]); | ||
reader.decoder = new Decoder(reader.fileHandle, reader.metadata.getSearchTreeSize() + DATA_SECTION_SEPARATOR_SIZE); | ||
return reader; | ||
}; | ||
@@ -29,3 +52,2 @@ | ||
; | ||
while (found <= mlen && fsize--) { | ||
@@ -38,6 +60,16 @@ found += (file[fsize] === METADATA_START_MARKER[mlen - found]) ? 1 : -found; | ||
Reader.prototype.get = function get(ipAddress) { | ||
Reader.prototype.getSync = function getSync(ipAddress) { | ||
var pointer = this.findAddressInTree(ipAddress); | ||
return (pointer === 0) ? null : this.resolveDataPointerSync(pointer); | ||
}; | ||
return (pointer === 0) ? null : this.resolveDataPointer(pointer); | ||
Reader.prototype.get = function get(ipAddress,callback) { | ||
var pointer = this.findAddressInTree(ipAddress); | ||
if(pointer === 0){ | ||
process.nextTick(function(){ | ||
callback(null,null); | ||
}); | ||
}else{ | ||
this.resolveDataPointer(pointer,callback); | ||
}; | ||
}; | ||
@@ -47,3 +79,3 @@ | ||
var bit, tempBit, record, | ||
rawAddress = ipAddress.split('.').map(function(v) { return parseInt(v, 10); }), | ||
rawAddress = IPParser(ipAddress), | ||
countRaw = rawAddress.length, | ||
@@ -78,3 +110,3 @@ isIp4AddressInIp6Db = (countRaw === 4 && this.metadata.getIpVersion() === 6), | ||
throw new Error('MaxmindDBReader: Unable to find IP:' + ipAddress + ' in Database'); | ||
return null; | ||
}; | ||
@@ -109,10 +141,19 @@ | ||
Reader.prototype.resolveDataPointer = function resolveDataPointer(pointer) { | ||
Reader.prototype.resolveDataPointerSync = function resolveDataPointerSync(pointer) { | ||
var resolved = pointer - this.metadata.getNodeCount() + this.metadata.getSearchTreeSize(); | ||
return this.decoder.decode(resolved)[0]; | ||
return this.decoder.decodeSync(resolved)[0]; | ||
}; | ||
Reader.prototype.resolveDataPointer = function resolveDataPointer(pointer,callback) { | ||
var resolved = pointer - this.metadata.getNodeCount() + this.metadata.getSearchTreeSize(); | ||
this.decoder.decode(resolved,function(err,data){ | ||
if(err) return callback(err); | ||
callback(null,data[0]); | ||
}); | ||
}; | ||
Reader.prototype.getMetadata = function metadata() { | ||
return this.metadata; | ||
}; |
{ | ||
"name" : "maxmind-db-reader", | ||
"version" : "0.0.2", | ||
"description" : "This is the pure Node API for reading MaxMind DB files. MaxMind DB is a binary file format that stores data indexed by IP address subnets (IPv4 or IPv6).", | ||
"main" : "./index.js", | ||
"repository" : { | ||
"type" : "git", | ||
"url" : "https://github.com/PaddeK/node-maxmind-db" | ||
"name": "maxmind-db-reader", | ||
"version": "0.2.0", | ||
"description": "This is the pure Node API for reading MaxMind DB files. MaxMind DB is a binary file format that stores data indexed by IP address subnets (IPv4 or IPv6).", | ||
"main": "./index.js", | ||
"contributors": [ | ||
{ | ||
"name": "Patrick Klös", | ||
"email": "pkloes@web.de" | ||
}, | ||
"keywords": [ | ||
"Maxmind", | ||
"Maxmind DB", | ||
"Maxmind DB Reader", | ||
"GeoIP2", | ||
"GeoIP2 Lite" | ||
], | ||
"author" : { | ||
"name" : "Patrick Klös", | ||
"email" : "pkloes@web.de" | ||
}, | ||
"dependencies" : { | ||
"big-integer" : ">=1.1.5" | ||
}, | ||
"licenses": [ | ||
{ | ||
"type": "LGPL 2.1", | ||
"url": "https://github.com/PaddeK/node-maxmind-db/blob/master/LICENSE" | ||
} | ||
], | ||
"engine" : { | ||
"node" : ">=0.8.0" | ||
{ | ||
"name": "Corné 'EaterOfCode' Oppelaar", | ||
"email": "hello@eaterofco.de" | ||
} | ||
} | ||
], | ||
"repository": { | ||
"type": "git", | ||
"url": "https://github.com/PaddeK/node-maxmind-db" | ||
}, | ||
"bin": { | ||
"mmdb-geoip": "./repl" | ||
}, | ||
"keywords": [ | ||
"Maxmind", | ||
"Maxmind DB", | ||
"Maxmind DB Reader", | ||
"GeoIP2", | ||
"GeoIP2 Lite" | ||
], | ||
"author": { | ||
"name": "Patrick Klös", | ||
"email": "pkloes@web.de" | ||
}, | ||
"dependencies": { | ||
"big-integer": ">=1.1.5" | ||
}, | ||
"licenses": [ | ||
{ | ||
"type": "LGPL 2.1", | ||
"url": "https://github.com/PaddeK/node-maxmind-db/blob/master/LICENSE" | ||
} | ||
], | ||
"engine": { | ||
"node": ">=0.8.0" | ||
} | ||
} |
148
README.md
@@ -1,4 +0,148 @@ | ||
node-maxmind-db | ||
=============== | ||
# node-maxmind-db | ||
This is the pure Node API for reading MaxMind DB files. MaxMind DB is a binary file format that stores data indexed by IP address subnets (IPv4 or IPv6). | ||
# WARNING | ||
* `.open(Sync)` needs to be called once before abusing `.getGeoData(Sync)` | ||
* this is version 0.1.0! the API is not compitable with 0.0.* | ||
* Most IP's don't seem to have city data in the GeoLite2 City database. Only american cities are present, if your IP is american but not returning a city try to replace the last number of your IP by a 0 (only with a IPv4 address. for IPv6 address it doesn't seem to work). | ||
# Install | ||
npm i https://github.com/EaterOfCode/node-maxmind-db/archive/master.tar.gz | ||
# Example | ||
## Async | ||
```javascript | ||
// require the db reader | ||
var mmdbreader = require('maxmind-db-reader'); | ||
// open database | ||
mmdbreader.open('./countries.mmdb',function(err,countries){ | ||
// get geodata | ||
countries.getGeoData('128.101.101.101',function(err,geodata){ | ||
// log data :D | ||
console.log(geodata); | ||
}); | ||
}); | ||
``` | ||
## Sync | ||
```javascript | ||
// require the db reader | ||
var mmdbreader = require('maxmind-db-reader'); | ||
// open database | ||
var countries = mmdbreader.openSync('./countries.mmdb'); | ||
// get geodata | ||
var geodata = countries.getGeoDataSync('128.101.101.101'); | ||
// log data :D | ||
console.log(geodata); | ||
``` | ||
## Mixed (Sync init, Async request) | ||
```javascript | ||
// require the db reader | ||
var mmdbreader = require('maxmind-db-reader'); | ||
// open database | ||
var countries = mmdbreader.openSync('./countries.mmdb'); | ||
// get geodata | ||
countries.getGeoData('128.101.101.101',function(err,geodata){ | ||
// log data :D | ||
console.log(geodata); | ||
}); | ||
``` | ||
## Result | ||
```javascript | ||
{ | ||
"city": { | ||
"geoname_id": 5037649, | ||
"names": { | ||
"de": "Minneapolis", | ||
"en": "Minneapolis", | ||
"es": "Mineápolis", | ||
"fr": "Minneapolis", | ||
"ja": "ミネアポリス", | ||
"pt-BR": "Minneapolis", | ||
"ru": "Миннеаполис", | ||
"zh-CN": "明尼阿波利斯" | ||
} | ||
}, | ||
"continent": { | ||
"code": "NA", | ||
"geoname_id": 6255149, | ||
"names": { | ||
"de": "Nordamerika", | ||
"en": "North America", | ||
"es": "Norteamérica", | ||
"fr": "Amérique du Nord", | ||
"ja": "北アメリカ", | ||
"pt-BR": "América do Norte", | ||
"ru": "Северная Америка", | ||
"zh-CN": "北美洲" | ||
} | ||
}, | ||
"country": { | ||
"geoname_id": 6252001, | ||
"iso_code": "US", | ||
"names": { | ||
"de": "USA", | ||
"en": "United States", | ||
"es": "Estados Unidos", | ||
"fr": "États-Unis", | ||
"ja": "アメリカ合衆国", | ||
"pt-BR": "Estados Unidos", | ||
"ru": "США", | ||
"zh-CN": "美国" | ||
} | ||
}, | ||
"location": { | ||
"latitude": 44.9759, | ||
"longitude": -93.2166, | ||
"metro_code": "613", | ||
"time_zone": "America/Chicago" | ||
}, | ||
"postal": { | ||
"code": "55414" | ||
}, | ||
"registered_country": { | ||
"geoname_id": 6252001, | ||
"iso_code": "US", | ||
"names": { | ||
"de": "USA", | ||
"en": "United States", | ||
"es": "Estados Unidos", | ||
"fr": "États-Unis", | ||
"ja": "アメリカ合衆国", | ||
"pt-BR": "Estados Unidos", | ||
"ru": "США", | ||
"zh-CN": "美国" | ||
} | ||
}, | ||
"subdivisions": [ | ||
{ | ||
"geoname_id": 5037779, | ||
"iso_code": "MN", | ||
"names": { | ||
"en": "Minnesota", | ||
"es": "Minnesota", | ||
"ja": "ミネソタ州", | ||
"ru": "Миннесота" | ||
} | ||
} | ||
] | ||
} | ||
``` | ||
# API | ||
`maxmind-db-reader` | ||
* `.open (databasePath, callback(err, maxmind-db-reader)) void` | ||
* `.openSync (databasePath) maxmind-db-reader` | ||
`maxmind-db-reader()` | ||
* `.getGeoData (ip, callback(err,geodata)) void` | ||
* `.getGeoDataSync (ip) geodata` | ||
* `.getDatabaseMetadata() metadata` |
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
Native code
Supply chain riskContains native code (e.g., compiled binaries or shared libraries). Including native code can obscure malicious behavior.
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
29607589
12
584
149
1