diff --git a/analytics.py b/analytics.py index eba9f28..b42502a 100644 --- a/analytics.py +++ b/analytics.py @@ -13,6 +13,9 @@ DB_NAME = 'access_log.db' # Create a single global connection to SQLite log_db = sqlite3.connect(DB_NAME, check_same_thread=False) +# geo location +geoReader = geoip2.database.Reader('GeoLite2-City.mmdb') + def init_log_db(): """Create the file_access_log table if it doesn't already exist.""" with log_db: @@ -23,7 +26,8 @@ def init_log_db(): rel_path TEXT, filesize INTEGER, mime TEXT, - ip_address TEXT, + city TEXT, + country TEXT, user_agent TEXT, device_id TEXT, cached BOOLEAN @@ -32,9 +36,9 @@ def init_log_db(): init_log_db() -def lookup_location(ip, reader): +def lookup_location(ip): try: - response = reader.city(ip) + response = geoReader.city(ip) country = response.country.name if response.country.name else "Unknown" city = response.city.name if response.city.name else "Unknown" return country, city @@ -97,12 +101,15 @@ def log_file_access(rel_path, filesize, mime, ip_address, user_agent, device_id, timestamp = datetime.now(timezone.utc).astimezone() iso_ts = timestamp.isoformat() + # Convert the IP address to a location + city, country = lookup_location(ip_address) + with log_db: log_db.execute(''' INSERT INTO file_access_log - (timestamp, rel_path, filesize, mime, ip_address, user_agent, device_id, cached) - VALUES (?, ?, ?, ?, ?, ?, ?, ?) - ''', (iso_ts, rel_path, filesize, mime, ip_address, user_agent, device_id, cached)) + (timestamp, rel_path, filesize, mime, city, country, user_agent, device_id, cached) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) + ''', (iso_ts, rel_path, filesize, mime, city, country, user_agent, device_id, cached)) # Remove entries older than 10 minutes using our robust parser. cutoff_time = datetime.now(timezone.utc).astimezone() - timedelta(minutes=10) @@ -112,7 +119,7 @@ def log_file_access(rel_path, filesize, mime, ip_address, user_agent, device_id, ] # Add the new entry at the beginning of the list - file_access_temp.insert(0, [iso_ts, rel_path, filesize, mime, ip_address, user_agent, device_id, cached]) + file_access_temp.insert(0, [iso_ts, rel_path, filesize, mime, f"{city}, {country}", user_agent, device_id, cached]) return True def return_file_access(): @@ -331,17 +338,17 @@ def dashboard(): folder_data.sort(key=lambda x: x['count'], reverse=True) folder_data = folder_data[:10] - # 6. Aggregate IP addresses with counts + # 6. Aggregate locations with counts query = f''' - SELECT ip_address, COUNT(*) as count + SELECT city, country, COUNT(*) as count FROM file_access_log WHERE timestamp >= ? {filetype_filter_sql} - GROUP BY ip_address + GROUP BY city ORDER BY count DESC ''' with log_db: cursor = log_db.execute(query, params_for_filter) - ip_rows = cursor.fetchall() + locations = cursor.fetchall() # 7. Summary stats # total_accesses @@ -387,14 +394,11 @@ def dashboard(): if cached_percentage is not None: cached_percentage = f"{cached_percentage:.2f}" - # 8. Process location data with GeoIP2 - reader = geoip2.database.Reader('GeoLite2-City.mmdb') + # 8. Process location data location_data_dict = {} - for (ip_addr, cnt) in ip_rows: - country, city = lookup_location(ip_addr, reader) + for (city, country, cnt) in locations: key = (country, city) location_data_dict[key] = location_data_dict.get(key, 0) + cnt - reader.close() location_data = [ dict(country=k[0], city=k[1], count=v) diff --git a/app.py b/app.py index cee0bb8..f439bfc 100755 --- a/app.py +++ b/app.py @@ -368,7 +368,7 @@ def query_recent_connections(): 'full_path': row[1], 'filesize': row[2], 'mime_typ': row[3], - 'ip_address': row[4], + 'location': row[4], 'user_agent': row[5], 'cached': row[7] } @@ -410,7 +410,7 @@ def handle_request_initial_data(): 'full_path': row[1], 'filesize' : row[2], 'mime_typ' : row[3], - 'ip_address': row[4], + 'location': row[4], 'user_agent': row[5], 'cached': row[7] } diff --git a/convert_ip.py b/convert_ip.py new file mode 100644 index 0000000..a4b936e --- /dev/null +++ b/convert_ip.py @@ -0,0 +1,80 @@ +#!/usr/bin/env python3 +import sqlite3 +import geoip2.database + +def get_location(ip_address, reader): + """ + Given an IP address, return the location in 'City, Country' format. + If the lookup fails, returns 'Unknown, Unknown'. + """ + try: + response = reader.city(ip_address) + city = response.city.name if response.city.name else "Unknown" + country = response.country.name if response.country.name else "Unknown" + return city, country + except Exception: + return "Unknown, Unknown" + +def main(): + # Initialize the GeoLite2 reader + reader = geoip2.database.Reader('GeoLite2-City.mmdb') + + # Connect to your SQLite database (update the path if necessary) + conn = sqlite3.connect('access_log.db') + conn.row_factory = sqlite3.Row # Enable name-based access to columns + cursor = conn.cursor() + + # Create a new table with the updated structure (location instead of ip_address) + cursor.execute(''' + CREATE TABLE IF NOT EXISTS file_access_log_new ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + timestamp TEXT, + rel_path TEXT, + filesize INTEGER, + mime TEXT, + city TEXT, + country TEXT, + user_agent TEXT, + device_id TEXT, + cached BOOLEAN + ) + ''') + conn.commit() + + # Read all rows from the old table + cursor.execute('SELECT * FROM file_access_log') + rows = cursor.fetchall() + + # Insert rows into the new table, converting IP addresses to locations + for row in rows: + timestamp = row['timestamp'] + rel_path = row['rel_path'] + filesize = row['filesize'] + mime = row['mime'] + ip_address = row['ip_address'] + city, country = get_location(ip_address, reader) + user_agent = row['user_agent'] + device_id = row['device_id'] + cached = row['cached'] + + cursor.execute(''' + INSERT INTO file_access_log_new + (timestamp, rel_path, filesize, mime, city, country, user_agent, device_id, cached) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) + ''', (timestamp, rel_path, filesize, mime, city, country, user_agent, device_id, cached)) + + conn.commit() + + # Optional: Replace the old table with the new table + cursor.execute('DROP TABLE file_access_log') + cursor.execute('ALTER TABLE file_access_log_new RENAME TO file_access_log') + conn.commit() + + # Clean up: close connections + conn.close() + reader.close() + + print("Database conversion complete.") + +if __name__ == '__main__': + main() diff --git a/templates/connections.html b/templates/connections.html index 6cc6b0d..c1763c5 100644 --- a/templates/connections.html +++ b/templates/connections.html @@ -44,7 +44,7 @@ Timestamp - IP Address + Location User Agent File Path File Size @@ -77,7 +77,7 @@ const row = document.createElement('tr'); row.innerHTML = ` ${record.timestamp} - ${record.ip_address} + ${record.location} ${record.user_agent} ${record.full_path} ${record.filesize}