Compare commits

...

2 Commits

11 changed files with 152 additions and 36 deletions

View File

@ -54,6 +54,7 @@ ENABLE_HTTPS_SECURITY=false
LOG_LEVEL=debug # debug | info | warning | error
# Database Path - Point to your MaxMind databases location
# Both GeoLite2-City.mmdb and GeoLite2-ASN.mmdb are required
MAXMIND_DB_PATH=D:\tools\maxmind-dbs # Windows
# MAXMIND_DB_PATH=/usr/share/maxmind # Linux/Mac
@ -188,12 +189,18 @@ Returns basic location information:
"ip": "8.8.8.8",
"country": "United States",
"country_code": "US",
"is_in_european_union": false,
"region": "California",
"region_code": "CA",
"city": "Mountain View",
"latitude": 37.4056,
"longitude": -122.0775,
"timezone": "America/Los_Angeles",
"postal_code": "94043"
"postal_code": "94043",
"continent_code": "NA",
"continent_name": "North America",
"organization": "Google LLC",
"asn": 15169
}
```
@ -376,19 +383,21 @@ npm run install:all # Install all dependencies (root + backend + frontend)
### MaxMind Database Setup
The service requires MaxMind GeoLite2-City database. You have two options:
The service requires both MaxMind GeoLite2-City and GeoLite2-ASN databases. You have two options:
**Option 1: Manual Download**
1. Sign up at https://www.maxmind.com/en/geolite2/signup
2. Download GeoLite2-City database (`.mmdb` file)
3. Place it in a directory (e.g., `D:\tools\maxmind-dbs` on Windows)
2. Download both databases (`.mmdb` files):
- GeoLite2-City.mmdb
- GeoLite2-ASN.mmdb
3. Place them in the same directory (e.g., `D:\tools\maxmind-dbs` on Windows)
4. Set `MAXMIND_DB_PATH` environment variable to that directory
**Option 2: Using geoipupdate (Production)**
- Use the provided `docker-compose.yml` which includes geoipupdate service
- geoipupdate automatically downloads and updates databases
- geoipupdate automatically downloads and updates both databases
- Both services share a Docker volume for database access
### Rate Limiting
@ -446,8 +455,8 @@ The service includes comprehensive health checks:
**1. Database Not Found**
- Ensure databases are downloaded to the path specified in `MAXMIND_DB_PATH`
- Check that `GeoLite2-City.mmdb` file exists in that directory
- Ensure both databases are downloaded to the path specified in `MAXMIND_DB_PATH`
- Check that both `GeoLite2-City.mmdb` and `GeoLite2-ASN.mmdb` files exist in that directory
- Verify file permissions (read access required)
**2. TypeScript Errors**

View File

@ -1,21 +1,21 @@
{
"title": "Bitip - Professional GeoIP Lookup Service",
"subtitle": "Modern GeoIP lookup service with REST API and interactive web interface",
"lastUpdated": "2025-10-05T14:00:00Z",
"lastUpdated": "2025-10-06T10:00:00Z",
"sections": [
{
"title": "Overview",
"content": "Bitip is a high-performance GeoIP lookup service designed to provide accurate geolocation data for IP addresses. Built with modern web technologies, it offers both a RESTful API for programmatic access and an intuitive web interface for interactive lookups. The service is built on the reliable MaxMind GeoLite2 database and provides real-time IP geolocation with detailed information including country, city, coordinates, timezone, and postal codes."
"content": "Bitip is a high-performance GeoIP lookup service designed to provide accurate geolocation data for IP addresses. Built with modern web technologies, it offers both a RESTful API for programmatic access and an intuitive web interface for interactive lookups. The service uses MaxMind GeoLite2-City and GeoLite2-ASN databases to provide comprehensive IP geolocation with detailed information including country, continent, region, city, coordinates, timezone, postal codes, EU membership status, ISP organization, and autonomous system numbers (ASN)."
},
{
"title": "Core Features",
"items": [
"**Single IP Lookup** - Get geolocation data for individual IP addresses with detailed information including country, city, coordinates, timezone, and postal code",
"**Single IP Lookup** - Get geolocation data for individual IP addresses with detailed information including country, continent, region, city, coordinates, timezone, postal code, EU membership, ISP organization, and ASN",
"**Batch IP Lookup** - Process up to 100 IP addresses in a single request for efficient bulk operations",
"**Dual API Access** - Separate authentication for frontend and external API consumers with different rate limiting profiles",
"**Origin Validation** - Security layer that validates request origins for frontend API keys to prevent unauthorized access",
"**Rate Limiting** - Configurable request limits per API key type (100 req/min for frontend, 1000 req/min for external)",
"**Real-time Lookup** - Instant geolocation results powered by MaxMind GeoLite2 City database",
"**Real-time Lookup** - Instant geolocation results powered by MaxMind GeoLite2-City and GeoLite2-ASN databases",
"**Interactive Web UI** - Modern, responsive interface for manual IP lookups with visual feedback and interactive maps",
"**RESTful API** - Clean, well-documented API endpoints for easy integration into your applications",
"**Docker Support** - Containerized deployment with Docker for easy setup and scalability",
@ -72,9 +72,9 @@
"items": [
"Endpoint: `GET /api/lookup/:ip`",
"Returns comprehensive geolocation data for a single IP address",
"Includes country, region, city, coordinates, timezone, and postal code",
"Includes country, continent, region (with ISO codes), city, coordinates, timezone, postal code, EU membership status, ISP organization, and ASN",
"Supports both IPv4 and IPv6 addresses",
"Returns detailed location hierarchy with ISO codes"
"Returns detailed location hierarchy with ISO codes and network information"
]
},
{
@ -230,7 +230,7 @@
},
{
"title": "Data Sources",
"content": "Bitip uses the **MaxMind GeoLite2 City** database, which provides accurate geolocation data for millions of IP addresses worldwide. The database is updated regularly by MaxMind and includes information about countries, regions, cities, coordinates, postal codes, and time zones. While GeoLite2 is a free version with good accuracy, MaxMind also offers premium databases with higher accuracy and additional data points for commercial applications."
"content": "Bitip uses both **MaxMind GeoLite2-City** and **MaxMind GeoLite2-ASN** databases, which provide accurate geolocation and network data for millions of IP addresses worldwide. The databases are updated regularly by MaxMind and include information about countries, continents, regions, cities, coordinates, postal codes, time zones, EU membership status, ISP organizations, and autonomous system numbers. While GeoLite2 is a free version with good accuracy, MaxMind also offers premium databases with higher accuracy and additional data points for commercial applications."
},
{
"title": "License",

View File

@ -1,5 +1,67 @@
{
"releases": [
{
"version": "1.1.0",
"date": "2025-10-06T10:00:00Z",
"title": "Enhanced GeoIP Data - ASN & Network Information",
"summary": "Added comprehensive network and geographic data by integrating MaxMind GeoLite2-ASN database alongside the existing City database. IP lookups now include ISP organization, ASN, continent information, region codes, and EU membership status.",
"sections": [
{
"title": "Overview",
"content": "Version 1.1.0 significantly expands the geolocation data provided by Bitip. By integrating the MaxMind GeoLite2-ASN database alongside the existing City database, the service now provides comprehensive network information including ISP organizations, autonomous system numbers (ASN), continent details, region ISO codes, and EU membership status. This enhancement makes Bitip more valuable for network diagnostics, fraud detection, and compliance use cases."
},
{
"title": "New Data Fields",
"items": [
"**EU Membership Status** - Boolean flag indicating if the IP's country is in the European Union",
"**Continent Information** - Continent name and ISO code (e.g., 'North America', 'NA')",
"**Region ISO Codes** - Standardized region/subdivision codes alongside names (e.g., 'California', 'CA')",
"**ISP Organization** - Name of the organization operating the autonomous system (e.g., 'Google LLC')",
"**Autonomous System Number (ASN)** - Network identifier for routing and network analysis (e.g., AS15169)"
]
},
{
"title": "Backend Enhancements",
"items": [
"**Dual Database Integration** - Added GeoLite2-ASN.mmdb reader alongside GeoLite2-City.mmdb",
"**Mandatory ASN Database** - Both databases are now required for service initialization",
"**Enhanced Type Definitions** - Updated TypeScript interfaces to include all new fields",
"**Merged Query Results** - Single API call queries both databases and merges results seamlessly",
"**Backward Compatible** - Existing API endpoints return enhanced data without breaking changes"
]
},
{
"title": "Frontend Updates",
"items": [
"**Enhanced UI Display** - All new fields visible in the web interface lookup results",
"**Improved Data Presentation** - Region and continent shown with ISO codes for clarity",
"**Network Information Section** - ISP organization and ASN displayed prominently",
"**EU Indicator** - Clear Yes/No display for European Union membership status",
"**Type Safety** - Frontend TypeScript types updated to match backend response structure"
]
},
{
"title": "Documentation Updates",
"items": [
"**README.md** - Updated API response examples with all new fields",
"**Database Requirements** - Documentation now specifies both GeoLite2-City and GeoLite2-ASN are required",
"**Setup Instructions** - Updated manual download and geoipupdate configuration guides",
"**Overview.json** - Enhanced feature descriptions and data source information",
"**API Documentation** - All endpoint examples reflect expanded response structure"
]
},
{
"title": "Use Case Benefits",
"items": [
"**Network Diagnostics** - ASN and organization data helps identify network routing and ISP information",
"**Fraud Detection** - Enhanced geographic and network data improves anomaly detection capabilities",
"**Compliance** - EU membership status aids GDPR and data residency compliance checks",
"**Analytics** - Continent and region codes enable better geographic grouping and reporting",
"**Security Monitoring** - ISP and ASN data provides additional context for access analysis"
]
}
]
},
{
"version": "1.0.4",
"date": "2025-10-05T20:30:00Z",

8
package-lock.json generated
View File

@ -1,12 +1,12 @@
{
"name": "bitip",
"version": "1.0.3",
"version": "1.0.4",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "bitip",
"version": "1.0.3",
"version": "1.0.4",
"license": "MIT",
"workspaces": [
"src/backend",
@ -6652,7 +6652,7 @@
},
"src/backend": {
"name": "bitip-backend",
"version": "1.0.3",
"version": "1.0.4",
"dependencies": {
"@maxmind/geoip2-node": "^6.1.0",
"compression": "^1.7.4",
@ -7141,7 +7141,7 @@
},
"src/frontend": {
"name": "bitip-frontend",
"version": "1.0.3",
"version": "1.0.4",
"dependencies": {
"@flare/utiliyo": "^1.2.2",
"axios": "^1.12.2",

View File

@ -1,7 +1,8 @@
{
"name": "bitip",
"version": "1.0.4",
"version": "1.1.0",
"description": "Bitip - GeoIP Lookup Service with REST API and Web Interface",
"type": "module",
"main": "dist/backend/index.js",
"scripts": {
"dev": "concurrently \"npm run dev:backend\" \"npm run dev:frontend\"",

View File

@ -1,6 +1,6 @@
{
"name": "bitip-backend",
"version": "1.0.4",
"version": "1.1.0",
"description": "Bitip Backend - GeoIP REST API Service",
"type": "module",
"main": "dist/index.js",

View File

@ -1,4 +1,4 @@
import { Reader, ReaderModel, City } from '@maxmind/geoip2-node';
import { Reader, ReaderModel, City, Asn } from '@maxmind/geoip2-node';
import path from 'path';
import fs from 'fs';
import NodeCache from 'node-cache';
@ -12,6 +12,7 @@ import logger from './logger';
class GeoIPService {
private cityReader?: ReaderModel;
private asnReader?: ReaderModel;
private cache: NodeCache;
private dbPath: string;
private isInitialized: boolean = false;
@ -25,15 +26,23 @@ class GeoIPService {
private async initializeReader(): Promise<void> {
try {
const cityDbPath = path.join(this.dbPath, 'GeoLite2-City.mmdb');
const asnDbPath = path.join(this.dbPath, 'GeoLite2-ASN.mmdb');
if (!fs.existsSync(cityDbPath)) {
throw new Error(`GeoIP database not found at ${cityDbPath}`);
throw new Error(`GeoIP City database not found at ${cityDbPath}`);
}
if (!fs.existsSync(asnDbPath)) {
throw new Error(`GeoIP ASN database not found at ${asnDbPath}`);
}
this.cityReader = await Reader.open(cityDbPath);
this.asnReader = await Reader.open(asnDbPath);
this.isInitialized = true;
logger.info('GeoIP database initialized successfully', {
dbPath: cityDbPath,
logger.info('GeoIP databases initialized successfully', {
cityDbPath,
asnDbPath,
});
} catch (error) {
logger.error('Failed to initialize GeoIP database', error as Error, {
@ -44,7 +53,7 @@ class GeoIPService {
}
private ensureInitialized(): void {
if (!this.isInitialized || !this.cityReader) {
if (!this.isInitialized || !this.cityReader || !this.asnReader) {
throw new Error('GeoIP service not initialized');
}
}
@ -60,17 +69,25 @@ class GeoIPService {
}
try {
const response: City = this.cityReader!.city(ip);
const cityResponse: City = this.cityReader!.city(ip);
const asnResponse: Asn = this.asnReader!.asn(ip);
const result: SimplifiedGeoIPResponse = {
ip,
country: response.country?.names?.en || 'Unknown',
country_code: response.country?.isoCode || 'XX',
region: response.subdivisions?.[0]?.names?.en || 'Unknown',
city: response.city?.names?.en || 'Unknown',
latitude: response.location?.latitude || null,
longitude: response.location?.longitude || null,
timezone: response.location?.timeZone || null,
postal_code: response.postal?.code || null,
country: cityResponse.country?.names?.en || 'Unknown',
country_code: cityResponse.country?.isoCode || 'XX',
is_in_european_union: cityResponse.country?.isInEuropeanUnion || false,
region: cityResponse.subdivisions?.[0]?.names?.en || 'Unknown',
region_code: cityResponse.subdivisions?.[0]?.isoCode || null,
city: cityResponse.city?.names?.en || 'Unknown',
latitude: cityResponse.location?.latitude || null,
longitude: cityResponse.location?.longitude || null,
timezone: cityResponse.location?.timeZone || null,
postal_code: cityResponse.postal?.code || null,
continent_code: cityResponse.continent?.code || null,
continent_name: cityResponse.continent?.names?.en || null,
organization: asnResponse.autonomousSystemOrganization || null,
asn: asnResponse.autonomousSystemNumber || null,
};
this.cache.set(cacheKey, result);

View File

@ -6,6 +6,7 @@ export interface GeoIPLocation {
country?: {
iso_code?: string;
names?: { [key: string]: string };
is_in_european_union?: boolean;
};
city?: {
names?: { [key: string]: string };
@ -40,12 +41,18 @@ export interface SimplifiedGeoIPResponse {
ip: string;
country: string;
country_code: string;
is_in_european_union: boolean;
region: string;
region_code: string | null;
city: string;
latitude: number | null;
longitude: number | null;
timezone: string | null;
postal_code: string | null;
continent_code: string | null;
continent_name: string | null;
organization: string | null;
asn: number | null;
}
export interface DetailedGeoIPResponse {

View File

@ -1,6 +1,6 @@
{
"name": "bitip-frontend",
"version": "1.0.4",
"version": "1.1.0",
"description": "Bitip Frontend - GeoIP Web Interface",
"type": "module",
"scripts": {

View File

@ -59,7 +59,19 @@ const Home: React.FC = () => {
const formatLocationData = (data: SimplifiedGeoIPResponse) => [
{ label: 'IP Address', value: data.ip },
{ label: 'Country', value: `${data.country} (${data.country_code})` },
{ label: 'Region', value: data.region },
{ label: 'EU Member', value: data.is_in_european_union ? 'Yes' : 'No' },
{
label: 'Continent',
value: data.continent_name
? `${data.continent_name} (${data.continent_code})`
: 'N/A',
},
{
label: 'Region',
value: data.region_code
? `${data.region} (${data.region_code})`
: data.region,
},
{ label: 'City', value: data.city },
{
label: 'Coordinates',
@ -70,6 +82,8 @@ const Home: React.FC = () => {
},
{ label: 'Timezone', value: data.timezone || 'N/A' },
{ label: 'Postal Code', value: data.postal_code || 'N/A' },
{ label: 'Organization', value: data.organization || 'N/A' },
{ label: 'ASN', value: data.asn ? `AS${data.asn}` : 'N/A' },
];
return (

View File

@ -36,12 +36,18 @@ export interface SimplifiedGeoIPResponse {
ip: string;
country: string;
country_code: string;
is_in_european_union: boolean;
region: string;
region_code: string | null;
city: string;
latitude: number | null;
longitude: number | null;
timezone: string | null;
postal_code: string | null;
continent_code: string | null;
continent_name: string | null;
organization: string | null;
asn: number | null;
}
export interface DetailedGeoIPResponse {