geoip_shop_manager.py aktualisiert

This commit is contained in:
2025-12-08 17:16:12 +01:00
parent 18d9b22ea6
commit eaa7eae038

View File

@@ -450,21 +450,24 @@ def get_active_shops():
return active
def activate_blocking(shop):
"""Activate GeoIP blocking"""
def activate_blocking(shop, silent=False):
"""Activate GeoIP blocking for a single shop"""
httpdocs = os.path.join(VHOSTS_DIR, shop, 'httpdocs')
index_php = os.path.join(httpdocs, 'index.php')
backup_php = os.path.join(httpdocs, f'index.php{BACKUP_SUFFIX}')
blocking_file = os.path.join(httpdocs, BLOCKING_FILE)
if os.path.isfile(backup_php):
if not silent:
print(f"⚠️ GeoIP-Blocking bereits aktiv für {shop}")
return False
if not os.path.isfile(index_php):
if not silent:
print(f"❌ index.php nicht gefunden")
return False
if not silent:
print(f"\n🔧 Aktiviere DACH GeoIP-Blocking für: {shop}")
print(" (Erlaubt: Deutschland, Österreich, Schweiz)")
print("=" * 60)
@@ -472,18 +475,22 @@ def activate_blocking(shop):
# Step 1: Install watcher service if not exists
active_shops = get_active_shops()
if not active_shops: # First shop
if not silent:
print("\n[1/3] Installiere CrowdSec-Watcher-Service...")
if check_crowdsec():
install_watcher_service()
else:
if not silent:
print(" ⚠️ CrowdSec nicht verfügbar - nur PHP-Blocking")
else:
if not silent:
print("\n[1/3] CrowdSec-Watcher-Service bereits aktiv")
# Step 2: PHP blocking
if not silent:
print("\n[2/3] Aktiviere PHP-Blocking...")
print(" 📋 Backup erstellen...")
shutil.copy2(index_php, backup_php)
with open(index_php, 'r', encoding='utf-8') as f:
@@ -505,6 +512,7 @@ def activate_blocking(shop):
lines.insert(insert_line, require_statement)
with open(index_php, 'w', encoding='utf-8') as f:
f.write('\n'.join(lines))
if not silent:
print(" ✏️ index.php modifiziert")
expiry = datetime.now() + timedelta(hours=72)
@@ -519,13 +527,17 @@ def activate_blocking(shop):
with open(blocking_file, 'w', encoding='utf-8') as f:
f.write(geoip_content)
if not silent:
print(" 📝 geoip_blocking.php erstellt")
# Step 3: Register shop
if not silent:
print("\n[3/3] Registriere Shop...")
add_shop_to_active(shop)
if not silent:
print(" ✅ Shop registriert")
if not silent:
print("\n" + "=" * 60)
print(f"✅ DACH GeoIP-Blocking aktiviert für: {shop}")
print(f" Erlaubte Länder: 🇩🇪 DE | 🇦🇹 AT | 🇨🇭 CH")
@@ -538,8 +550,8 @@ def activate_blocking(shop):
return True
def deactivate_blocking(shop):
"""Deactivate GeoIP blocking"""
def deactivate_blocking(shop, silent=False):
"""Deactivate GeoIP blocking for a single shop"""
httpdocs = os.path.join(VHOSTS_DIR, shop, 'httpdocs')
index_php = os.path.join(httpdocs, 'index.php')
backup_php = os.path.join(httpdocs, f'index.php{BACKUP_SUFFIX}')
@@ -548,14 +560,17 @@ def deactivate_blocking(shop):
log_file = os.path.join(httpdocs, LOG_FILE)
queue_file = os.path.join(httpdocs, CROWDSEC_QUEUE_FILE)
if not silent:
print(f"\n🔧 Deaktiviere DACH GeoIP-Blocking für: {shop}")
print("=" * 60)
# Step 1: Remove PHP blocking
if not silent:
print("\n[1/4] PHP-Blocking entfernen...")
if os.path.isfile(backup_php):
shutil.move(backup_php, index_php)
if not silent:
print(" 📋 index.php wiederhergestellt")
else:
if os.path.isfile(index_php):
@@ -568,27 +583,35 @@ def deactivate_blocking(shop):
for f in [blocking_file, cache_file, log_file, queue_file]:
if os.path.isfile(f):
os.remove(f)
if not silent:
print(" 🗑️ PHP-Dateien gelöscht")
# Step 2: Remove from tracking
if not silent:
print("\n[2/4] Deregistriere Shop...")
remove_shop_from_active(shop)
if not silent:
print(" ✅ Shop deregistriert")
# Step 3: Clean CrowdSec decisions
if not silent:
print("\n[3/4] CrowdSec-Decisions entfernen...")
if check_crowdsec():
cleanup_crowdsec_decisions(shop)
# Step 4: Uninstall service if last shop
if not silent:
print("\n[4/4] Prüfe Watcher-Service...")
remaining_shops = [s for s in get_active_shops() if s != shop]
if not remaining_shops:
if not silent:
print(" Keine aktiven Shops mehr - deinstalliere Service")
uninstall_watcher_service()
else:
if not silent:
print(f" Service bleibt aktiv ({len(remaining_shops)} Shop(s) noch aktiv)")
if not silent:
print("\n" + "=" * 60)
print(f"✅ DACH GeoIP-Blocking deaktiviert für: {shop}")
print("=" * 60)
@@ -596,8 +619,335 @@ def deactivate_blocking(shop):
return True
def activate_all_shops():
"""Activate GeoIP blocking for all available shops"""
shops = get_available_shops()
active_shops = get_active_shops()
available_shops = [s for s in shops if s not in active_shops]
if not available_shops:
print("\n⚠️ Keine Shops zum Aktivieren verfügbar")
print(" Alle Shops haben bereits aktives GeoIP-Blocking")
return
print(f"\n{'=' * 60}")
print(f" DACH GeoIP-Blocking für ALLE Shops aktivieren")
print(f"{'=' * 60}")
print(f"\n📋 Folgende {len(available_shops)} Shop(s) werden aktiviert:\n")
for shop in available_shops:
print(f"{shop}")
print(f"\n⚠️ Dies aktiviert den Schutz für alle oben genannten Shops!")
confirm = input(f"\nFortfahren? (ja/nein): ").strip().lower()
if confirm not in ['ja', 'j', 'yes', 'y']:
print("\n❌ Abgebrochen")
return
print(f"\n{'=' * 60}")
print(" Starte Aktivierung...")
print(f"{'=' * 60}")
success_count = 0
failed_count = 0
failed_shops = []
# Install watcher service first if needed
if not active_shops and check_crowdsec():
print("\n📦 Installiere CrowdSec-Watcher-Service...")
install_watcher_service()
for i, shop in enumerate(available_shops, 1):
print(f"\n[{i}/{len(available_shops)}] Aktiviere: {shop}")
try:
# Use silent mode but show progress
httpdocs = os.path.join(VHOSTS_DIR, shop, 'httpdocs')
index_php = os.path.join(httpdocs, 'index.php')
backup_php = os.path.join(httpdocs, f'index.php{BACKUP_SUFFIX}')
blocking_file = os.path.join(httpdocs, BLOCKING_FILE)
if os.path.isfile(backup_php):
print(f" ⚠️ Bereits aktiv - überspringe")
continue
if not os.path.isfile(index_php):
print(f" ❌ index.php nicht gefunden")
failed_count += 1
failed_shops.append(shop)
continue
# Create backup
shutil.copy2(index_php, backup_php)
# Modify index.php
with open(index_php, 'r', encoding='utf-8') as f:
content = f.read()
lines = content.split('\n')
insert_line = 0
for idx, line in enumerate(lines):
if 'declare(strict_types' in line:
insert_line = idx + 1
break
elif '<?php' in line and insert_line == 0:
insert_line = idx + 1
require_statement = f"require_once __DIR__ . '/{BLOCKING_FILE}';"
if require_statement not in content:
lines.insert(insert_line, require_statement)
with open(index_php, 'w', encoding='utf-8') as f:
f.write('\n'.join(lines))
# Create blocking script
expiry = datetime.now() + timedelta(hours=72)
geoip_content = GEOIP_SCRIPT.format(
expiry_date=expiry.strftime('%Y-%m-%d %H:%M:%S CET'),
expiry_timestamp=expiry.strftime('%Y-%m-%d %H:%M:%S'),
cache_file=CACHE_FILE,
log_file=LOG_FILE,
crowdsec_queue=CROWDSEC_QUEUE_FILE,
shop_name=shop
)
with open(blocking_file, 'w', encoding='utf-8') as f:
f.write(geoip_content)
# Register shop
add_shop_to_active(shop)
print(f" ✅ Aktiviert (bis {expiry.strftime('%Y-%m-%d %H:%M')})")
success_count += 1
except Exception as e:
print(f" ❌ Fehler: {e}")
failed_count += 1
failed_shops.append(shop)
# Summary
print(f"\n{'=' * 60}")
print(" ZUSAMMENFASSUNG")
print(f"{'=' * 60}")
print(f"\n ✅ Erfolgreich aktiviert: {success_count}")
print(f" ❌ Fehlgeschlagen: {failed_count}")
if failed_shops:
print(f"\n Fehlgeschlagene Shops:")
for shop in failed_shops:
print(f"{shop}")
print(f"\n 🇩🇪 🇦🇹 🇨🇭 Nur DACH-Traffic erlaubt")
print(f" ⏰ Gültig für 72 Stunden")
print(f"{'=' * 60}")
def deactivate_all_shops():
"""Deactivate GeoIP blocking for all active shops"""
active_shops = get_active_shops()
if not active_shops:
print("\n⚠️ Keine Shops mit aktivem GeoIP-Blocking gefunden")
return
print(f"\n{'=' * 60}")
print(f" DACH GeoIP-Blocking für ALLE Shops deaktivieren")
print(f"{'=' * 60}")
print(f"\n📋 Folgende {len(active_shops)} Shop(s) werden deaktiviert:\n")
for shop in active_shops:
print(f"{shop}")
print(f"\n⚠️ Dies deaktiviert den Schutz für alle oben genannten Shops!")
print(f"⚠️ Alle zugehörigen CrowdSec-Decisions werden ebenfalls entfernt!")
confirm = input(f"\nFortfahren? (ja/nein): ").strip().lower()
if confirm not in ['ja', 'j', 'yes', 'y']:
print("\n❌ Abgebrochen")
return
print(f"\n{'=' * 60}")
print(" Starte Deaktivierung...")
print(f"{'=' * 60}")
success_count = 0
failed_count = 0
failed_shops = []
for i, shop in enumerate(active_shops, 1):
print(f"\n[{i}/{len(active_shops)}] Deaktiviere: {shop}")
try:
httpdocs = os.path.join(VHOSTS_DIR, shop, 'httpdocs')
index_php = os.path.join(httpdocs, 'index.php')
backup_php = os.path.join(httpdocs, f'index.php{BACKUP_SUFFIX}')
blocking_file = os.path.join(httpdocs, BLOCKING_FILE)
cache_file = os.path.join(httpdocs, CACHE_FILE)
log_file_path = os.path.join(httpdocs, LOG_FILE)
queue_file = os.path.join(httpdocs, CROWDSEC_QUEUE_FILE)
# Restore backup
if os.path.isfile(backup_php):
shutil.move(backup_php, index_php)
print(f" 📋 index.php wiederhergestellt")
else:
if os.path.isfile(index_php):
with open(index_php, 'r') as f:
content = f.read()
lines = [line for line in content.split('\n') if BLOCKING_FILE not in line]
with open(index_php, 'w') as f:
f.write('\n'.join(lines))
# Remove files
for f in [blocking_file, cache_file, log_file_path, queue_file]:
if os.path.isfile(f):
os.remove(f)
# Remove from tracking
remove_shop_from_active(shop)
# Clean CrowdSec decisions
if check_crowdsec():
cleanup_crowdsec_decisions(shop)
print(f" ✅ Deaktiviert")
success_count += 1
except Exception as e:
print(f" ❌ Fehler: {e}")
failed_count += 1
failed_shops.append(shop)
# Uninstall watcher service
print("\n📦 Deinstalliere CrowdSec-Watcher-Service...")
uninstall_watcher_service()
# Summary
print(f"\n{'=' * 60}")
print(" ZUSAMMENFASSUNG")
print(f"{'=' * 60}")
print(f"\n ✅ Erfolgreich deaktiviert: {success_count}")
print(f" ❌ Fehlgeschlagen: {failed_count}")
if failed_shops:
print(f"\n Fehlgeschlagene Shops:")
for shop in failed_shops:
print(f"{shop}")
print(f"\n 🌍 Alle IPs sind nun wieder erlaubt")
print(f"{'=' * 60}")
def get_shop_log_stats(shop):
"""Get log statistics for a single shop"""
httpdocs = os.path.join(VHOSTS_DIR, shop, 'httpdocs')
log_file = os.path.join(httpdocs, LOG_FILE)
php_blocks = 0
ips = {}
if os.path.isfile(log_file):
with open(log_file, 'r') as f:
for line in f:
php_blocks += 1
# Extract IP from log line
if 'IP: ' in line:
try:
ip = line.split('IP: ')[1].split(' |')[0].strip()
ips[ip] = ips.get(ip, 0) + 1
except:
pass
return php_blocks, ips
def get_crowdsec_stats_by_shop():
"""Get CrowdSec decision counts grouped by shop"""
if not check_crowdsec():
return {}
stats = {}
code, stdout, _ = run_command("cscli decisions list -o raw")
if code == 0 and stdout:
lines = stdout.strip().split('\n')
for line in lines[1:]: # Skip header
# Find shop name in reason field
for shop in get_active_shops():
if shop in line:
stats[shop] = stats.get(shop, 0) + 1
break
return stats
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{'' * 60}")
print(" 📊 GESAMTÜBERSICHT ALLER SHOPS")
print(f"{'' * 60}")
total_php_blocks = 0
shop_php_stats = {}
all_ips = {}
# Collect PHP stats
for shop in active_shops:
blocks, ips = get_shop_log_stats(shop)
total_php_blocks += blocks
shop_php_stats[shop] = blocks
for ip, count in ips.items():
all_ips[ip] = all_ips.get(ip, 0) + count
# Get CrowdSec stats
crowdsec_stats = get_crowdsec_stats_by_shop()
total_crowdsec = sum(crowdsec_stats.values())
# Display PHP blocks
print(f"\n📝 PHP-Blocks gesamt: {total_php_blocks}")
if shop_php_stats:
for shop in sorted(shop_php_stats.keys()):
count = shop_php_stats[shop]
bar = "" * min(count // 10, 20) if count > 0 else ""
print(f" ├─ {shop}: {count} {bar}")
# 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 ""
print(f" ├─ {shop}: {count} {bar}")
elif check_crowdsec():
print(" └─ Keine aktiven Bans")
else:
print(" └─ CrowdSec nicht verfügbar")
# Top blocked IPs
if all_ips:
print(f"\n🔥 Top 10 blockierte IPs (alle Shops):")
sorted_ips = sorted(all_ips.items(), key=lambda x: x[1], reverse=True)[:10]
for ip, count in sorted_ips:
bar = "" * min(count // 5, 20) if count > 0 else ""
print(f" {ip}: {count} {bar}")
print(f"\n{'' * 60}")
# Wait for user
input("\nDrücke Enter um fortzufahren...")
def show_logs(shop):
"""Show logs"""
"""Show logs for a single shop"""
httpdocs = os.path.join(VHOSTS_DIR, shop, 'httpdocs')
log_file = os.path.join(httpdocs, LOG_FILE)
@@ -677,10 +1027,15 @@ def main():
print(" ⚠️ Watcher-Service: Nicht aktiv")
while True:
print("\n[1] GeoIP-Blocking AKTIVIEREN")
print("[2] GeoIP-Blocking DEAKTIVIEREN")
print("\n" + "-" * 40)
print("[1] GeoIP-Blocking AKTIVIEREN (einzeln)")
print("[2] GeoIP-Blocking DEAKTIVIEREN (einzeln)")
print("[3] Logs anzeigen")
print("[4] Status anzeigen")
print("-" * 40)
print("[5] 🚀 ALLE Shops aktivieren")
print("[6] 🛑 ALLE Shops deaktivieren")
print("-" * 40)
print("[0] Beenden")
choice = input("\nWähle eine Option: ").strip()
@@ -741,17 +1096,22 @@ def main():
print("\n⚠️ Keine aktiven Shops")
continue
print("\n📋 Shops mit Logs:")
print("\n📋 Logs anzeigen für:")
print(f" [0] 📊 ALLE Shops (Zusammenfassung)")
for i, shop in enumerate(active_shops, 1):
print(f" [{i}] {shop}")
shop_choice = input("\nWähle einen Shop: ").strip()
shop_choice = input("\nWähle eine Option: ").strip()
try:
shop_idx = int(shop_choice) - 1
if 0 <= shop_idx < len(active_shops):
show_logs(active_shops[shop_idx])
shop_idx = int(shop_choice)
if shop_idx == 0:
show_all_logs()
elif 1 <= shop_idx <= len(active_shops):
show_logs(active_shops[shop_idx - 1])
else:
print("❌ Ungültig")
except ValueError:
pass
print("❌ Ungültig")
elif choice == "4":
shops = get_available_shops()
@@ -763,6 +1123,12 @@ def main():
for shop in active_shops:
print(f"{shop}")
elif choice == "5":
activate_all_shops()
elif choice == "6":
deactivate_all_shops()
elif choice == "0":
print("\n👋 Auf Wiedersehen!")
break