diff --git a/geoip_shop_manager.py b/geoip_shop_manager.py index 8718c44..c8028a1 100644 --- a/geoip_shop_manager.py +++ b/geoip_shop_manager.py @@ -10,7 +10,7 @@ Supports three modes: - php-only: GeoIP blocking without CrowdSec - bot-only: Block only bots, shop remains globally accessible -v3.4.0: Added file-based rate-limiting for bot blocking +v3.4.2: Fixed directory permissions for rate-limit (777 for PHP access) """ import os @@ -1158,9 +1158,13 @@ def activate_blocking(shop, silent=False, mode="php+crowdsec", geo_region="dach" # Select appropriate template if is_bot_mode: - # Create rate-limit directories - os.makedirs(os.path.join(ratelimit_path, 'bans'), exist_ok=True) - os.makedirs(os.path.join(ratelimit_path, 'counts'), exist_ok=True) + # Create rate-limit directories with open permissions (PHP runs as different user) + os.makedirs(os.path.join(ratelimit_path, 'bans'), mode=0o777, exist_ok=True) + os.makedirs(os.path.join(ratelimit_path, 'counts'), mode=0o777, exist_ok=True) + # Ensure parent dir also has correct permissions + os.chmod(ratelimit_path, 0o777) + os.chmod(os.path.join(ratelimit_path, 'bans'), 0o777) + os.chmod(os.path.join(ratelimit_path, 'counts'), 0o777) # Use defaults if not specified if rate_limit is None: @@ -1399,9 +1403,12 @@ def activate_all_shops(): expiry = datetime.now() + timedelta(hours=72) if is_bot_mode: - # Create rate-limit directories - os.makedirs(os.path.join(ratelimit_path, 'bans'), exist_ok=True) - os.makedirs(os.path.join(ratelimit_path, 'counts'), exist_ok=True) + # Create rate-limit directories with open permissions (PHP runs as different user) + os.makedirs(os.path.join(ratelimit_path, 'bans'), mode=0o777, exist_ok=True) + os.makedirs(os.path.join(ratelimit_path, 'counts'), mode=0o777, exist_ok=True) + os.chmod(ratelimit_path, 0o777) + os.chmod(os.path.join(ratelimit_path, 'bans'), 0o777) + os.chmod(os.path.join(ratelimit_path, 'counts'), 0o777) if uses_crowdsec(mode): template = BOT_ONLY_SCRIPT_TEMPLATE @@ -1559,9 +1566,12 @@ def activate_direct_shops_only(): expiry = datetime.now() + timedelta(hours=72) if is_bot_mode: - # Create rate-limit directories - os.makedirs(os.path.join(ratelimit_path, 'bans'), exist_ok=True) - os.makedirs(os.path.join(ratelimit_path, 'counts'), exist_ok=True) + # Create rate-limit directories with open permissions (PHP runs as different user) + os.makedirs(os.path.join(ratelimit_path, 'bans'), mode=0o777, exist_ok=True) + os.makedirs(os.path.join(ratelimit_path, 'counts'), mode=0o777, exist_ok=True) + os.chmod(ratelimit_path, 0o777) + os.chmod(os.path.join(ratelimit_path, 'bans'), 0o777) + os.chmod(os.path.join(ratelimit_path, 'counts'), 0o777) if uses_crowdsec(mode): template = BOT_ONLY_SCRIPT_TEMPLATE @@ -1714,8 +1724,12 @@ def get_shop_log_stats(shop): if ip: if ip not in ips: - ips[ip] = {'count': 0, 'ua': ua} + ips[ip] = {'count': 0, 'ua': ua, 'bot': None} ips[ip]['count'] += 1 + # Store bot name if detected (from BOT: or BANNED: in log) + if detected_bot and not ips[ip]['bot']: + ips[ip]['bot'] = detected_bot + # Fallback: try to detect from UA if we have one if ua != 'Unknown' and ips[ip]['ua'] == 'Unknown': ips[ip]['ua'] = ua @@ -1793,7 +1807,8 @@ def show_logs(shop): if ips: print(f"\nšŸ”„ Top 10 IPs:") for ip, data in sorted(ips.items(), key=lambda x: x[1]['count'], reverse=True)[:10]: - bot = detect_bot(data['ua']) + # Use stored bot name first, fallback to UA detection + bot = data.get('bot') or detect_bot(data['ua']) print(f" {ip} ({bot}): {data['count']}x") @@ -1848,11 +1863,14 @@ def show_all_logs(): for ip, data in ips.items(): if ip not in all_ips: - all_ips[ip] = {'count': 0, 'ua': data['ua'], 'shops': {}} + all_ips[ip] = {'count': 0, 'ua': data['ua'], 'bot': data.get('bot'), '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'] + # Update bot name if we have one + if data.get('bot') and not all_ips[ip].get('bot'): + all_ips[ip]['bot'] = data.get('bot') for bot_name, count in bots.items(): all_bots[bot_name] = all_bots.get(bot_name, 0) + count @@ -1905,7 +1923,8 @@ def show_all_logs(): 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) + # Use stored bot name first, fallback to UA detection + top_ip_bot = top_ip[1].get('bot') or detect_bot(top_ip_ua) top_ip_req_min = top_ip_count / runtime if runtime > 0 else 0 if top_ip_bot == 'Unbekannt': @@ -1973,7 +1992,8 @@ def show_all_logs(): for ip, data in sorted_ips: count = data['count'] ua = data['ua'] - bot_name = detect_bot(ua) + # Use stored bot name first, fallback to UA detection + bot_name = data.get('bot') or detect_bot(ua) shops_data = data['shops'] # Calculate req/min for this IP @@ -2014,7 +2034,7 @@ def show_all_logs(): def main(): print("\n" + "=" * 60) - print(" GeoIP Shop Blocker Manager v3.4.0") + print(" GeoIP Shop Blocker Manager v3.4.2") print(" šŸ‡©šŸ‡ŖšŸ‡¦šŸ‡¹šŸ‡ØšŸ‡­ DACH | šŸ‡ŖšŸ‡ŗ Eurozone+GB | šŸ¤– Bot-Only") print(" šŸ›”ļø Mit Cache-Validierung und Fail-Open") print(" 🚦 Mit File-basiertem Rate-Limiting")