From 1df13e41e332771645708c9ccedad75363277b11 Mon Sep 17 00:00:00 2001 From: thomasciesla Date: Tue, 9 Dec 2025 12:03:54 +0100 Subject: [PATCH] geoip_shop_manager.py aktualisiert --- geoip_shop_manager.py | 166 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 150 insertions(+), 16 deletions(-) diff --git a/geoip_shop_manager.py b/geoip_shop_manager.py index 6683b60..6cebe0c 100644 --- a/geoip_shop_manager.py +++ b/geoip_shop_manager.py @@ -1033,44 +1033,178 @@ def show_logs(shop): def show_all_logs(): + """Show combined logs for all active shops""" active_shops = get_active_shops() + if not active_shops: print("\n⚠️ Keine aktiven Shops") return print(f"\n{'═' * 70}") - print(" 📊 GESAMTÜBERSICHT") + print(" 📊 GESAMTÜBERSICHT ALLER SHOPS") print(f"{'═' * 70}") + print(f" {COLOR_GREEN}Grün = hinter Link11{COLOR_RESET} | {COLOR_RED}Rot = Direkt{COLOR_RESET}") - total_blocks = 0 - all_ips = {} + total_php_blocks = 0 + shop_php_stats = {} # shop -> {'blocks': N, 'runtime_minutes': float, 'req_min': float, 'ips': {}} + all_ips = {} # ip -> {'count': N, 'ua': user_agent, 'shops': {shop: count}} + total_minutes = 0 + # Collect PHP stats for shop in active_shops: blocks, ips, activation_time = get_shop_log_stats(shop) - total_blocks += blocks - region_info = get_geo_region_info(get_shop_geo_region(shop)) + total_php_blocks += blocks - runtime = (datetime.now() - activation_time).total_seconds() / 60 if activation_time else 0 - req_min = blocks / runtime if runtime > 0 else 0 + # Calculate runtime and req/min + if activation_time: + runtime_minutes = (datetime.now() - activation_time).total_seconds() / 60 + req_min = blocks / runtime_minutes if runtime_minutes > 0 else 0 + else: + runtime_minutes = 0 + req_min = 0 - link11_info = check_link11(shop) - color = COLOR_GREEN if link11_info['is_link11'] else COLOR_RED + shop_php_stats[shop] = { + 'blocks': blocks, + 'runtime_minutes': runtime_minutes, + 'req_min': req_min, + 'ips': ips + } - print(f" {color}{shop}{COLOR_RESET} {region_info['icon']}: {blocks} ({req_min:.1f} req/min)") + if runtime_minutes > total_minutes: + total_minutes = runtime_minutes for ip, data in ips.items(): if ip not in all_ips: - all_ips[ip] = {'count': 0, 'ua': data['ua']} + all_ips[ip] = {'count': 0, 'ua': data['ua'], 'shops': {}} all_ips[ip]['count'] += data['count'] + all_ips[ip]['shops'][shop] = data['count'] + if data['ua'] != 'Unknown' and all_ips[ip]['ua'] == 'Unknown': + all_ips[ip]['ua'] = data['ua'] - print(f"\n📊 Gesamt: {total_blocks} Blocks") + # Calculate total req/min + total_req_min = total_php_blocks / total_minutes if total_minutes > 0 else 0 + # Get CrowdSec stats + crowdsec_stats = {} + if check_crowdsec(): + code, stdout, _ = run_command("cscli decisions list -o raw --limit 0") + if code == 0 and stdout: + for line in stdout.strip().split('\n')[1:]: + for shop in active_shops: + if shop in line: + crowdsec_stats[shop] = crowdsec_stats.get(shop, 0) + 1 + break + total_crowdsec = sum(crowdsec_stats.values()) + + # Display PHP blocks with req/min and top IP per shop + print(f"\n📝 PHP-Blocks gesamt: {total_php_blocks} (⌀ {total_req_min:.1f} req/min, Laufzeit: {format_duration(total_minutes)})") + if shop_php_stats: + for shop in sorted(shop_php_stats.keys()): + stats = shop_php_stats[shop] + count = stats['blocks'] + req_min = stats['req_min'] + runtime = stats['runtime_minutes'] + bar = "█" * min(int(req_min * 2), 20) if req_min > 0 else "" + runtime_str = format_duration(runtime) if runtime > 0 else "?" + + # Get geo region icon + geo_region = get_shop_geo_region(shop) + region_info = get_geo_region_info(geo_region) + geo_icon = region_info['icon'] + + # Color shop name based on Link11 status + link11_info = check_link11(shop) + if link11_info['is_link11']: + shop_colored = f"{COLOR_GREEN}{shop}{COLOR_RESET}" + else: + shop_colored = f"{COLOR_RED}{shop}{COLOR_RESET}" + + print(f" ├─ {shop_colored} {geo_icon}: {count} ({req_min:.1f} req/min, seit {runtime_str}) {bar}") + + # Show top IP for this shop + shop_ips = stats['ips'] + if shop_ips and count > 0: + top_ip = max(shop_ips.items(), key=lambda x: x[1]['count']) + top_ip_addr = top_ip[0] + top_ip_count = top_ip[1]['count'] + top_ip_ua = top_ip[1]['ua'] + top_ip_bot = detect_bot(top_ip_ua) + top_ip_req_min = top_ip_count / runtime if runtime > 0 else 0 + + if top_ip_bot == 'Unbekannt': + display_name = (top_ip_ua[:40] + '...') if len(top_ip_ua) > 43 else top_ip_ua + else: + display_name = top_ip_bot + + print(f" │ └─➤ Top: {top_ip_addr} ({display_name}) - {top_ip_count}x, {top_ip_req_min:.1f} req/min") + + # Display CrowdSec bans + print(f"\n🛡️ CrowdSec-Bans gesamt: {total_crowdsec}") + if crowdsec_stats: + for shop in sorted(crowdsec_stats.keys()): + count = crowdsec_stats[shop] + bar = "█" * min(count // 10, 20) if count > 0 else "" + + geo_region = get_shop_geo_region(shop) + region_info = get_geo_region_info(geo_region) + geo_icon = region_info['icon'] + + link11_info = check_link11(shop) + if link11_info['is_link11']: + shop_colored = f"{COLOR_GREEN}{shop}{COLOR_RESET}" + else: + shop_colored = f"{COLOR_RED}{shop}{COLOR_RESET}" + + print(f" ├─ {shop_colored} {geo_icon}: {count} {bar}") + elif check_crowdsec(): + print(" └─ Keine aktiven Bans") + else: + print(" └─ CrowdSec nicht verfügbar") + + # Top 50 blocked IPs with bot detection, req/min, and top shop if all_ips: - print(f"\n🔥 Top 20 IPs:") - for ip, data in sorted(all_ips.items(), key=lambda x: x[1]['count'], reverse=True)[:20]: - print(f" {ip} ({detect_bot(data['ua'])}): {data['count']}x") + print(f"\n🔥 Top 50 blockierte IPs (alle Shops):") + sorted_ips = sorted(all_ips.items(), key=lambda x: x[1]['count'], reverse=True)[:50] + for ip, data in sorted_ips: + count = data['count'] + ua = data['ua'] + bot_name = detect_bot(ua) + shops_data = data['shops'] + + # Calculate req/min for this IP + ip_req_min = count / total_minutes if total_minutes > 0 else 0 + + # Find top shop for this IP + if shops_data: + top_shop = max(shops_data.items(), key=lambda x: x[1]) + top_shop_name = top_shop[0] + top_shop_count = top_shop[1] + if len(top_shop_name) > 25: + top_shop_short = top_shop_name[:22] + '...' + else: + top_shop_short = top_shop_name + + link11_info = check_link11(top_shop_name) + if link11_info['is_link11']: + top_shop_display = f"{COLOR_GREEN}{top_shop_short}{COLOR_RESET}" + else: + top_shop_display = f"{COLOR_RED}{top_shop_short}{COLOR_RESET}" + else: + top_shop_display = "?" + top_shop_count = 0 + + if bot_name == 'Unbekannt': + display_name = (ua[:35] + '...') if len(ua) > 38 else ua + if display_name == 'Unknown': + display_name = 'Unbekannt' + else: + display_name = bot_name + + bar = "█" * min(count // 5, 20) if count > 0 else "█" + print(f" {ip} ({display_name}): {count} ({ip_req_min:.1f} req/min) → {top_shop_display} [{top_shop_count}x] {bar}") - input("\nEnter zum Fortfahren...") + print(f"\n{'═' * 70}") + input("\nDrücke Enter um fortzufahren...") def main():