ipdb
Version:
IP lookup using IPIP.net database (Node.js & Browser)
297 lines (239 loc) • 7.54 kB
JavaScript
'use strict';
var require$$0 = require('fs');
function getDefaultExportFromCjs (x) {
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
}
var src = {exports: {}};
var hasRequiredSrc;
function requireSrc () {
if (hasRequiredSrc) return src.exports;
hasRequiredSrc = 1;
(function (module, exports$1) {
// Pure JavaScript IP validation (replaces net.isIP)
function isIP(ip) {
// IPv4 validation
const ipv4Regex = /^(25[0-5]|2[0-4]\d|[01]?\d{1,2})\.(25[0-5]|2[0-4]\d|[01]?\d{1,2})\.(25[0-5]|2[0-4]\d|[01]?\d{1,2})\.(25[0-5]|2[0-4]\d|[01]?\d{1,2})$/;
if (ipv4Regex.test(ip)) {
const parts = ip.split('.');
for (const part of parts) {
const num = parseInt(part, 10);
if (num > 255) {
return 0
}
}
return 4
}
// IPv6 validation (supports :: compression)
if (ip.includes(':')) {
const parts = ip.split(':');
const hasDoubleColon = ip.includes('::');
// Check basic format validity
if (!hasDoubleColon && parts.length !== 8) {
return 0
}
if (hasDoubleColon && parts.length > 8) {
return 0
}
for (const part of parts) {
if (part === '') {
continue
}
if (!/^[\da-f]{1,4}$/i.test(part)) {
return 0
}
}
return 6
}
return 0
}
// Buffer-compatible read functions using DataView
function readInt32BE(buffer, offset) {
if (buffer.readInt32BE) {
return buffer.readInt32BE(offset)
}
// False = Big Endian
const view = new DataView(buffer.buffer, buffer.byteOffset + offset, 4);
return view.getInt32(0, false)
}
function readUInt16BE(buffer, offset) {
if (buffer.readUInt16BE) {
return buffer.readUInt16BE(offset)
}
const view = new DataView(buffer.buffer, buffer.byteOffset + offset, 2);
return view.getUint16(0, false)
}
function readUInt32BE(buffer, offset) {
if (buffer.readUInt32BE) {
return buffer.readUInt32BE(offset)
}
const view = new DataView(buffer.buffer, buffer.byteOffset + offset, 4);
return view.getUint32(0, false)
}
const isBuffer = obj => {
// Support both Node.js Buffer and Uint8Array
if (obj instanceof Uint8Array) {
return true
}
return obj !== null && obj.constructor !== null &&
typeof obj.constructor.isBuffer === 'function' && obj.constructor.isBuffer(obj)
};
class Parse {
constructor(filename, options = {}) {
let data;
// Environment detection: file path only supported in Node.js
if (typeof filename === 'string') {
if (typeof process !== 'undefined' && process.versions && process.versions.node) {
// Node.js environment
const fs = require$$0;
data = fs.readFileSync(filename);
} else {
throw new Error('File path is only supported in Node.js environment. In browser, please pass ArrayBuffer or Uint8Array.')
}
} else if (isBuffer(filename)) {
data = filename;
} else if (filename instanceof ArrayBuffer) {
data = new Uint8Array(filename);
} else if (filename instanceof Uint8Array) {
data = filename;
} else {
throw new TypeError('Invalid input type. Expected: file path (Node.js only), Buffer, ArrayBuffer, or Uint8Array')
}
const metaLen = readInt32BE(data, 0);
const meta = data.slice(4, 4 + metaLen);
// Convert Uint8Array to string
let metaStr;
if (typeof TextDecoder === 'undefined') {
metaStr = meta.toString();
} else {
metaStr = new TextDecoder().decode(meta);
}
this.meta = JSON.parse(metaStr);
this.data = data.slice(4 + metaLen);
if (options.patches) {
this.patches = options.patches;
}
if (this.meta.v4node === undefined && this.meta.ip_version & 0x01) {
this._initv4node();
}
}
_initv4node() {
let node = 0;
for (let i = 0; i < 80; i += 1) {
node = this._node(node, 0);
}
for (let i = 80; i < 96; i += 1) {
node = this._node(node, 1);
}
this.meta.v4node = node;
}
find(ip, options = {}) {
const result = {};
try {
result.data = this._find(ip, options.language);
result.code = 0;
if (this.patches || options.patches) {
const patches = options.patches || this.patches;
for (const patch of patches) {
patch(result.data);
}
}
} catch (error) {
result.code = -1;
result.message = error.message;
}
return result
}
_find(ip, language) {
const bits = this._toBits(ip);
let node = bits.length === 32 ? this.meta.v4node : 0;
let cidr = 0;
while (cidr < bits.length) {
node = this._node(node, bits[cidr]);
cidr += 1;
if (node >= this.meta.node_count) {
break
}
}
const data = this._resolve(node);
let offset = 0;
if (this.meta.languages[language]) {
offset = this.meta.languages[language];
}
const result = {};
for (let i = 0; i < this.meta.fields.length; i += 1) {
result[this.meta.fields[i]] = data[offset + i];
}
result.ip = ip;
result.bitmask = cidr;
return result
}
_resolve(node) {
const offset = node + (this.meta.node_count << 3) - this.meta.node_count;
const len = readUInt16BE(this.data, offset);
const buf = this.data.slice(offset + 2, offset + 2 + len);
// Convert to string
let str;
if (typeof TextDecoder === 'undefined') {
str = buf.toString();
} else {
str = new TextDecoder().decode(buf);
}
return str.split('\t')
}
_node(id, idx) {
return readUInt32BE(this.data, (id << 3) | (idx << 2))
}
_toBits(ip) {
const version = isIP(ip);
if (!version) {
throw new Error('ip format error')
}
if (version === 4 && !(this.meta.ip_version & 0x01)) {
throw new Error('no support ipv4')
}
if (version === 6 && !(this.meta.ip_version & 0x02)) {
throw new Error('no support ipv6')
}
return version === 4 ? this._toBits4(ip) : this._toBits6(ip)
}
_toBits4(ip) {
const result = [];
const items = ip.split('.');
for (const item of items) {
const num = parseInt(item, 10);
for (let i = 7; i >= 0; i -= 1) {
result.push((num >> i) & 1);
}
}
return result
}
_toBits6(ip) {
const result = [[], []];
const parts = ip.split('::', 2);
for (let index = 0; index < 2; index += 1) {
if (parts[index]) {
const items = parts[index].split(':');
for (const item of items) {
const num = parseInt(item, 16);
for (let i = 15; i >= 0; i -= 1) {
result[index].push((num >> i) & 1);
}
}
}
}
const pad = 128 - result[0].length - result[1].length;
return [...result[0], ...(new Array(pad).fill(0)), ...result[1]]
}
}
module.exports = Parse;
// ESM export support
{
exports$1.default = Parse;
exports$1.Parse = Parse;
}
} (src, src.exports));
return src.exports;
}
var srcExports = requireSrc();
var index = /*@__PURE__*/getDefaultExportFromCjs(srcExports);
module.exports = index;