UNPKG

node_js_ipqs_db_reader

Version:

A Node JS implementation of the IPQualityScore flat file IP reputation database reader.

334 lines (333 loc) 13.9 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); const FileReader_1 = require("./FileReader"); const Binary = require("./BinaryOption"); const AbuseVelocity_1 = require("./AbuseVelocity"); const ConnectionType_1 = require("./ConnectionType"); const FraudScore_1 = require("./FraudScore"); const Column_1 = require("./Column"); class IPQSRecord { constructor(file) { this.isProxy = false; this.isVPN = false; this.isTOR = false; this.isCrawler = false; this.isBot = false; this.recentAbuse = false; this.isBlacklisted = false; this.isPrivate = false; this.isMobile = false; this.hasOpenPorts = false; this.isHostingProvider = false; this.activeVPN = false; this.activeTOR = false; this.publicAccessPoint = false; this.connectionType = null; this.abuseVelocity = null; this.country = null; this.city = null; this.region = null; this.ISP = null; this.organization = null; this.ASN = null; this.timezone = null; this.latitude = null; this.longitude = null; this.fraudScore = null; this.columns = []; this.valid = false; this.position = 0; this.literal = ""; this.file_position = 0; this.previous = {}; this.file = file; } fetch(ip) { return __awaiter(this, void 0, void 0, function* () { this.position = 0; this.previous = {}; this.file_position = this.file.treeStart + FileReader_1.default.TREE_PREFIX_BYTES; this.literal = this.convertIPToLitteral(this.file.IPv6, ip); return yield this.populateRecord(0); }); } populateRecord(iterations) { return __awaiter(this, void 0, void 0, function* () { if (iterations > 256) { throw new Error("Invalid or nonexistent IP address specified for lookup. (EID: 15)"); } if (this.file.fileHandler === undefined) { throw new Error("Invalid or nonexistant file pointer. EID 7"); } this.previous[this.position] = this.file_position; if (this.literal.length <= this.position) { throw new Error("Invalid or nonexistent IP address specified for lookup. (EID: 8)"); } try { let read = Buffer.alloc(IPQSRecord.TREE_BYTES); yield this.file.fileHandler.read(read, 0, // offset in the buffer to start reading IPQSRecord.TREE_BYTES, // number of bytes to read this.file_position // position in the file to start reading from ); if (this.literal[this.position] === "0") { this.file_position = read.readUInt32LE(0); } else { this.file_position = read.readUInt32LE(4); } if (this.file.blacklistFile === false) { if (this.file_position === 0) { for (let i = 0; i <= this.position; i++) { if (this.literal[this.position - i] === "1") { let bf = this.literal.split(""); bf[this.position - i] = "0"; for (let n = this.position - i + 1; n < bf.length; n++) { bf[n] = "1"; } this.literal = bf.join(""); this.position = this.position - i; this.file_position = this.previous[this.position]; break; } } return this.populateRecord(iterations + 1); } } if (this.file_position < this.file.treeEnd) { if (this.file_position === 0) { throw new Error("Invalid or nonexistent IP address specified for lookup. (EID: 12)"); } this.position++; return this.populateRecord(iterations + 1); } if (this.file.fileHandler === undefined) { throw new Error("Invalid or nonexistant file pointer. EID 7"); } let raw = Buffer.alloc(this.file.recordBytes); const { bytesRead } = yield this.file.fileHandler.read(raw, 0, // offset in the buffer to start reading this.file.recordBytes, // number of bytes to read this.file_position // position in the file to start reading from ); if (bytesRead === 0) { throw new Error("Invalid or nonexistant file pointer. EID 7"); } return yield this.parseRecord(raw); } catch (err) { throw err; } }); } parseRecord(raw) { var _a; return __awaiter(this, void 0, void 0, function* () { let current_byte = 0; if (this.file.binaryData === undefined) { throw new Error("Invalid or nonexistant file. EID 11"); } if (this.file.binaryData.has(Binary.BinaryData)) { this.processFirstByte(new Binary.Bitmask(raw[0])); this.processSecondByte(new Binary.Bitmask(raw[1])); let third = new Binary.Bitmask(raw[2]); this.connectionType = new ConnectionType_1.default(third); this.abuseVelocity = new AbuseVelocity_1.default(third); current_byte = 3; } else { let first = new Binary.Bitmask(raw[0]); this.connectionType = new ConnectionType_1.default(first); this.abuseVelocity = new AbuseVelocity_1.default(first); current_byte = 1; } this.fraudScore = new FraudScore_1.default(); for (let i = 0; i < this.file.columns.length; i++) { let c = this.file.columns[i]; if (c === undefined) { throw new Error("Invalid or nonexistent IP address specified for lookup. (EID: 12)"); } let value = ""; switch (c.name) { case "ASN": this.ASN = raw.readUInt32LE(current_byte); value = (_a = this.ASN) === null || _a === void 0 ? void 0 : _a.toString(); current_byte += 4; break; case "Latitude": this.latitude = raw.readFloatLE(current_byte); value = this.latitude.toString(); current_byte += 4; break; case "Longitude": this.longitude = raw.readFloatLE(current_byte); value = this.longitude.toString(); current_byte += 4; break; case "ZeroFraudScore": this.fraudScore.setFraudScore(0, raw.readUInt8(current_byte)); value = this.fraudScore.getFraudScore(0).toString(); current_byte++; break; case "OneFraudScore": this.fraudScore.setFraudScore(1, raw.readUInt8(current_byte)); value = this.fraudScore.getFraudScore(1).toString(); current_byte++; break; default: if (c.type.has(Binary.StringData)) { const pos = raw.readUInt32LE(current_byte); if (!this.file.fileHandler) { throw new Error("Invalid or nonexistent file pointer. EID 13"); } try { const sb = Buffer.alloc(1); const { bytesRead: bytesRead1 } = yield this.file.fileHandler.read(sb, 0, 1, pos); if (bytesRead1 !== 1) { throw new Error("Failed to read string size byte. EID 13a"); } const size = sb.readUInt8(0); if (size === 0) { throw new Error("Invalid or nonexistent file pointer. EID 14"); } const vb = Buffer.alloc(size); const { bytesRead: bytesRead2 } = yield this.file.fileHandler.read(vb, 0, size, pos + 1); if (bytesRead2 !== size) { throw new Error("Failed to read string value. EID 13b"); } value = vb.toString(); current_byte += 4; } catch (err) { throw new Error(`File read error: ${err.message}`); } } break; } this.columns.push(new Column_1.default(c.name, c.type, value)); switch (c.name) { case "Country": this.country = value; break; case "City": this.city = value; break; case "Region": this.region = value; break; case "ISP": this.ISP = value; break; case "Organization": this.organization = value; break; case "Timezone": this.timezone = value; break; } } this.valid = true; this.position = 0; this.literal = ""; this.previous = {}; this.file_position = 0; return; }); } processFirstByte(b) { if (b.has(Binary.IsProxy)) { this.isProxy = true; } if (b.has(Binary.IsVPN)) { this.isVPN = true; } if (b.has(Binary.IsTOR)) { this.isTOR = true; } if (b.has(Binary.IsCrawler)) { this.isCrawler = true; } if (b.has(Binary.IsBot)) { this.isBot = true; } if (b.has(Binary.RecentAbuse)) { this.recentAbuse = true; } if (b.has(Binary.IsBlacklisted)) { this.isBlacklisted = true; } if (b.has(Binary.IsPrivate)) { this.isPrivate = true; } } processSecondByte(b) { if (b.has(Binary.IsMobile)) { this.isMobile = true; } if (b.has(Binary.HasOpenPorts)) { this.hasOpenPorts = true; } if (b.has(Binary.IsHostingProvider)) { this.isHostingProvider = true; } if (b.has(Binary.ActiveVPN)) { this.activeVPN = true; } if (b.has(Binary.ActiveTOR)) { this.activeTOR = true; } if (b.has(Binary.PublicAccessPoint)) { this.publicAccessPoint = true; } } convertIPToLitteral(ipv6, ip) { let result = ""; if (ipv6) { let parts = this.expandIPv6(ip).split(":"); for (let i = 0; i < parts.length; i++) { result = result + parseInt(parts[i], 16).toString(2).padStart(16, "0"); } } else { let parts = ip.split("."); for (let i = 0; i < parts.length; i++) { result = result + parseInt(parts[i]).toString(2).padStart(8, "0"); } } return result; } expandIPv6(ip) { if (ip.indexOf("::") === -1) { return ip; } let length = 8; let result = ""; let sides = ip.split("::"); var groupsPresent = 0; for (var i = 0; i < sides.length; i++) { groupsPresent += sides[i].split(":").length; } let fullAddress = sides[0] + ":"; for (var i = 0; i < length - groupsPresent; i++) { fullAddress += "0000:"; } fullAddress += sides[1]; let groups = fullAddress.split(":"); for (var i = 0; i < length; i++) { while (groups[i].length < 4) { groups[i] = "0" + groups[i]; } result += i != length - 1 ? groups[i] + ":" : groups[i]; } return result; } } exports.default = IPQSRecord; IPQSRecord.TREE_BYTES = 8;