# app.py from flask import Flask, request, render_template, g import sqlite3 import requests from datetime import datetime import os app = Flask(__name__) app.config['DATABASE'] = 'visitors.db' app.config['IP_API_KEY'] = '' # Optional API key for ip-api.com # Database setup def get_db(): db = getattr(g, '_database', None) if db is None: db = g._database = sqlite3.connect(app.config['DATABASE']) return db def init_db(): with app.app_context(): db = get_db() cursor = db.cursor() cursor.execute(''' CREATE TABLE IF NOT EXISTS visitors ( id INTEGER PRIMARY KEY AUTOINCREMENT, timestamp TEXT NOT NULL, ip TEXT NOT NULL, country TEXT, country_code TEXT, region TEXT, region_name TEXT, city TEXT, zip TEXT, lat REAL, lon REAL, timezone TEXT, isp TEXT, org TEXT, as_number TEXT, mobile BOOLEAN, proxy BOOLEAN, hosting BOOLEAN, user_agent TEXT, path TEXT ) ''') db.commit() @app.teardown_appcontext def close_connection(exception): db = getattr(g, '_database', None) if db is not None: db.close() # Helper functions def get_client_ip(): """Get the client IP address, handling proxy headers""" if request.headers.getlist("X-Forwarded-For"): ip = request.headers.getlist("X-Forwarded-For")[0].split(',')[0] else: ip = request.remote_addr return ip def get_location_info(ip_address): """Get geolocation information for an IP address""" try: # Using ip-api.com (free tier) fields = 'status,message,country,countryCode,region,regionName,city,zip,lat,lon,timezone,isp,org,as,mobile,proxy,hosting,query' url = f'http://ip-api.com/json/{ip_address}?fields={fields}' if app.config['IP_API_KEY']: url += f'&key={app.config["IP_API_KEY"]}' response = requests.get(url, timeout=5) data = response.json() if data.get('status') == 'success': return data return {'error': data.get('message', 'Unknown error')} except Exception as e: return {'error': str(e)} def log_visitor(ip, location_info): """Store visitor information in the database""" db = get_db() cursor = db.cursor() cursor.execute(''' INSERT INTO visitors ( timestamp, ip, country, country_code, region, region_name, city, zip, lat, lon, timezone, isp, org, as_number, mobile, proxy, hosting, user_agent, path ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ''', ( datetime.now().isoformat(), ip, location_info.get('country'), location_info.get('countryCode'), location_info.get('region'), location_info.get('regionName'), location_info.get('city'), location_info.get('zip'), location_info.get('lat'), location_info.get('lon'), location_info.get('timezone'), location_info.get('isp'), location_info.get('org'), location_info.get('as'), bool(location_info.get('mobile')), bool(location_info.get('proxy')), bool(location_info.get('hosting')), request.headers.get('User-Agent'), request.path )) db.commit() # Routes @app.route('/') def index(): client_ip = get_client_ip() location_info = get_location_info(client_ip) if 'error' not in location_info: log_visitor(client_ip, location_info) return render_template('index.html', ip=client_ip, location=location_info, error=location_info.get('error')) @app.route('/visitors') def show_visitors(): """Admin view to see all recorded visitors""" db = get_db() cursor = db.cursor() cursor.execute('SELECT * FROM visitors ORDER BY timestamp DESC LIMIT 100') visitors = cursor.fetchall() # Get column names cursor.execute('PRAGMA table_info(visitors)') columns = [column[1] for column in cursor.fetchall()] return render_template('visitors.html', visitors=visitors, columns=columns) if __name__ == '__main__': if not os.path.exists(app.config['DATABASE']): init_db() app.run(host="0.0.0.0", debug=True)