geoip_shop_manager.py aktualisiert
This commit is contained in:
@@ -5,8 +5,12 @@ GeoIP Shop Blocker Manager - DACH & Eurozone Version
|
|||||||
Supports two geo regions:
|
Supports two geo regions:
|
||||||
- DACH: Germany, Austria, Switzerland (3 countries)
|
- DACH: Germany, Austria, Switzerland (3 countries)
|
||||||
- Eurozone+GB: All Eurozone countries + GB + CH (22 countries)
|
- Eurozone+GB: All Eurozone countries + GB + CH (22 countries)
|
||||||
|
Supports three modes:
|
||||||
|
- php+crowdsec: GeoIP blocking with CrowdSec integration
|
||||||
|
- php-only: GeoIP blocking without CrowdSec
|
||||||
|
- bot-only: Block only bots, shop remains globally accessible
|
||||||
|
|
||||||
v3.1.0: Cache validation on activation + fail-open in PHP
|
v3.2.0: Added bot-only blocking mode
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import os
|
import os
|
||||||
@@ -71,6 +75,13 @@ GEO_REGIONS = {
|
|||||||
"description": "22 Länder: DE, AT, CH, BE, CY, EE, ES, FI, FR, GB, GR, HR, IE, IT, LT, LU, LV, MT, NL, PT, SI, SK",
|
"description": "22 Länder: DE, AT, CH, BE, CY, EE, ES, FI, FR, GB, GR, HR, IE, IT, LT, LU, LV, MT, NL, PT, SI, SK",
|
||||||
"icon": "🇪🇺",
|
"icon": "🇪🇺",
|
||||||
"short": "EU+"
|
"short": "EU+"
|
||||||
|
},
|
||||||
|
"none": {
|
||||||
|
"name": "Bot-Only",
|
||||||
|
"countries": [],
|
||||||
|
"description": "Nur Bot-Blocking, weltweit erreichbar",
|
||||||
|
"icon": "🤖",
|
||||||
|
"short": "BOT"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -136,6 +147,15 @@ def generate_php_countries_array(geo_region):
|
|||||||
return ", ".join([f"'{c}'" for c in region_info["countries"]])
|
return ", ".join([f"'{c}'" for c in region_info["countries"]])
|
||||||
|
|
||||||
|
|
||||||
|
def generate_php_bot_patterns():
|
||||||
|
"""Generate PHP array of bot patterns"""
|
||||||
|
patterns = []
|
||||||
|
for bot_name, pattern in BOT_PATTERNS.items():
|
||||||
|
escaped_pattern = pattern.replace("'", "\\'")
|
||||||
|
patterns.append(f"'{bot_name}' => '/{escaped_pattern}/i'")
|
||||||
|
return ",\n ".join(patterns)
|
||||||
|
|
||||||
|
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
# CACHE VALIDATION
|
# CACHE VALIDATION
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
@@ -392,6 +412,82 @@ if (!$is_allowed) {{
|
|||||||
}}
|
}}
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
BOT_ONLY_SCRIPT_TEMPLATE = '''<?php
|
||||||
|
/**
|
||||||
|
* Bot Blocking Script - Worldwide Access
|
||||||
|
* Valid until: {expiry_date}
|
||||||
|
* Blocks known bots/crawlers, allows all human traffic globally
|
||||||
|
*/
|
||||||
|
|
||||||
|
$expiry_date = strtotime('{expiry_timestamp}');
|
||||||
|
if (time() > $expiry_date) return;
|
||||||
|
|
||||||
|
$log_file = __DIR__ . '/{log_file}';
|
||||||
|
$crowdsec_queue = __DIR__ . '/{crowdsec_queue}';
|
||||||
|
|
||||||
|
$bot_patterns = [
|
||||||
|
{bot_patterns}
|
||||||
|
];
|
||||||
|
|
||||||
|
$user_agent = $_SERVER['HTTP_USER_AGENT'] ?? '';
|
||||||
|
if (empty($user_agent)) return;
|
||||||
|
|
||||||
|
$detected_bot = null;
|
||||||
|
foreach ($bot_patterns as $bot_name => $pattern) {{
|
||||||
|
if (preg_match($pattern, $user_agent)) {{
|
||||||
|
$detected_bot = $bot_name;
|
||||||
|
break;
|
||||||
|
}}
|
||||||
|
}}
|
||||||
|
|
||||||
|
if ($detected_bot !== null) {{
|
||||||
|
$timestamp = date('Y-m-d H:i:s');
|
||||||
|
$visitor_ip = $_SERVER['REMOTE_ADDR'] ?? 'Unknown';
|
||||||
|
$uri = $_SERVER['REQUEST_URI'] ?? '/';
|
||||||
|
@file_put_contents($log_file, "[$timestamp] BOT: $detected_bot | IP: $visitor_ip | UA: $user_agent | URI: $uri\\n", FILE_APPEND | LOCK_EX);
|
||||||
|
@file_put_contents($crowdsec_queue, "$timestamp|$visitor_ip|{shop_name}\\n", FILE_APPEND | LOCK_EX);
|
||||||
|
header('HTTP/1.1 403 Forbidden');
|
||||||
|
exit;
|
||||||
|
}}
|
||||||
|
'''
|
||||||
|
|
||||||
|
BOT_ONLY_SCRIPT_TEMPLATE_NO_CROWDSEC = '''<?php
|
||||||
|
/**
|
||||||
|
* Bot Blocking Script - Worldwide Access (No CrowdSec)
|
||||||
|
* Valid until: {expiry_date}
|
||||||
|
* Blocks known bots/crawlers, allows all human traffic globally
|
||||||
|
*/
|
||||||
|
|
||||||
|
$expiry_date = strtotime('{expiry_timestamp}');
|
||||||
|
if (time() > $expiry_date) return;
|
||||||
|
|
||||||
|
$log_file = __DIR__ . '/{log_file}';
|
||||||
|
|
||||||
|
$bot_patterns = [
|
||||||
|
{bot_patterns}
|
||||||
|
];
|
||||||
|
|
||||||
|
$user_agent = $_SERVER['HTTP_USER_AGENT'] ?? '';
|
||||||
|
if (empty($user_agent)) return;
|
||||||
|
|
||||||
|
$detected_bot = null;
|
||||||
|
foreach ($bot_patterns as $bot_name => $pattern) {{
|
||||||
|
if (preg_match($pattern, $user_agent)) {{
|
||||||
|
$detected_bot = $bot_name;
|
||||||
|
break;
|
||||||
|
}}
|
||||||
|
}}
|
||||||
|
|
||||||
|
if ($detected_bot !== null) {{
|
||||||
|
$timestamp = date('Y-m-d H:i:s');
|
||||||
|
$visitor_ip = $_SERVER['REMOTE_ADDR'] ?? 'Unknown';
|
||||||
|
$uri = $_SERVER['REQUEST_URI'] ?? '/';
|
||||||
|
@file_put_contents($log_file, "[$timestamp] BOT: $detected_bot | IP: $visitor_ip | UA: $user_agent | URI: $uri\\n", FILE_APPEND | LOCK_EX);
|
||||||
|
header('HTTP/1.1 403 Forbidden');
|
||||||
|
exit;
|
||||||
|
}}
|
||||||
|
'''
|
||||||
|
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
# WATCHER SERVICE
|
# WATCHER SERVICE
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
@@ -446,9 +542,12 @@ def main():
|
|||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
active_shops = get_active_shops()
|
active_shops = get_active_shops()
|
||||||
for shop in active_shops:
|
for shop, info in active_shops.items():
|
||||||
shop_path = os.path.join(VHOSTS_DIR, shop)
|
# Only process shops with CrowdSec enabled
|
||||||
if os.path.isdir(shop_path): process_queue_file(shop_path, shop)
|
mode = info.get('mode', 'php+crowdsec')
|
||||||
|
if mode in ['php+crowdsec', 'bot+crowdsec']:
|
||||||
|
shop_path = os.path.join(VHOSTS_DIR, shop)
|
||||||
|
if os.path.isdir(shop_path): process_queue_file(shop_path, shop)
|
||||||
time.sleep(CHECK_INTERVAL)
|
time.sleep(CHECK_INTERVAL)
|
||||||
except KeyboardInterrupt: break
|
except KeyboardInterrupt: break
|
||||||
except: time.sleep(CHECK_INTERVAL)
|
except: time.sleep(CHECK_INTERVAL)
|
||||||
@@ -635,6 +734,11 @@ def get_active_shops():
|
|||||||
return active
|
return active
|
||||||
|
|
||||||
|
|
||||||
|
def get_crowdsec_modes():
|
||||||
|
"""Return list of modes that use CrowdSec"""
|
||||||
|
return ['php+crowdsec', 'bot+crowdsec']
|
||||||
|
|
||||||
|
|
||||||
def select_geo_region():
|
def select_geo_region():
|
||||||
print(f"\n🌍 Wähle die Geo-Region:")
|
print(f"\n🌍 Wähle die Geo-Region:")
|
||||||
print(f" [1] {GEO_REGIONS['dach']['icon']} DACH - {GEO_REGIONS['dach']['description']}")
|
print(f" [1] {GEO_REGIONS['dach']['icon']} DACH - {GEO_REGIONS['dach']['description']}")
|
||||||
@@ -644,9 +748,51 @@ def select_geo_region():
|
|||||||
|
|
||||||
def select_mode():
|
def select_mode():
|
||||||
print(f"\n🔧 Wähle den Blocking-Modus:")
|
print(f"\n🔧 Wähle den Blocking-Modus:")
|
||||||
print(f" [1] PHP + CrowdSec (IPs werden an CrowdSec gemeldet)")
|
print(f" [1] 🌍 GeoIP + CrowdSec (IPs werden an CrowdSec gemeldet)")
|
||||||
print(f" [2] Nur PHP (keine CrowdSec-Synchronisation)")
|
print(f" [2] 🌍 Nur GeoIP (keine CrowdSec-Synchronisation)")
|
||||||
return "php-only" if input(f"\nModus wählen [1/2]: ").strip() == "2" else "php+crowdsec"
|
print(f" [3] 🤖 Nur Bot-Blocking (weltweit erreichbar, mit CrowdSec)")
|
||||||
|
print(f" [4] 🤖 Nur Bot-Blocking (weltweit erreichbar, ohne CrowdSec)")
|
||||||
|
|
||||||
|
choice = input(f"\nModus wählen [1/2/3/4]: ").strip()
|
||||||
|
if choice == "2":
|
||||||
|
return "php-only"
|
||||||
|
elif choice == "3":
|
||||||
|
return "bot+crowdsec"
|
||||||
|
elif choice == "4":
|
||||||
|
return "bot-only"
|
||||||
|
return "php+crowdsec"
|
||||||
|
|
||||||
|
|
||||||
|
def get_mode_icon(mode):
|
||||||
|
"""Return icon for mode"""
|
||||||
|
icons = {
|
||||||
|
'php+crowdsec': '🛡️',
|
||||||
|
'php-only': '📝',
|
||||||
|
'bot+crowdsec': '🤖🛡️',
|
||||||
|
'bot-only': '🤖'
|
||||||
|
}
|
||||||
|
return icons.get(mode, '❓')
|
||||||
|
|
||||||
|
|
||||||
|
def get_mode_description(mode):
|
||||||
|
"""Return description for mode"""
|
||||||
|
descriptions = {
|
||||||
|
'php+crowdsec': 'GeoIP + CrowdSec',
|
||||||
|
'php-only': 'Nur GeoIP',
|
||||||
|
'bot+crowdsec': 'Bot-Block + CrowdSec',
|
||||||
|
'bot-only': 'Nur Bot-Block'
|
||||||
|
}
|
||||||
|
return descriptions.get(mode, mode)
|
||||||
|
|
||||||
|
|
||||||
|
def is_bot_only_mode(mode):
|
||||||
|
"""Check if mode is bot-only"""
|
||||||
|
return mode in ['bot-only', 'bot+crowdsec']
|
||||||
|
|
||||||
|
|
||||||
|
def uses_crowdsec(mode):
|
||||||
|
"""Check if mode uses CrowdSec"""
|
||||||
|
return mode in ['php+crowdsec', 'bot+crowdsec']
|
||||||
|
|
||||||
|
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
@@ -659,12 +805,19 @@ def activate_blocking(shop, silent=False, mode="php+crowdsec", geo_region="dach"
|
|||||||
backup_php = os.path.join(httpdocs, f'index.php{BACKUP_SUFFIX}')
|
backup_php = os.path.join(httpdocs, f'index.php{BACKUP_SUFFIX}')
|
||||||
blocking_file = os.path.join(httpdocs, BLOCKING_FILE)
|
blocking_file = os.path.join(httpdocs, BLOCKING_FILE)
|
||||||
|
|
||||||
region_info = get_geo_region_info(geo_region)
|
is_bot_mode = is_bot_only_mode(mode)
|
||||||
|
|
||||||
|
if is_bot_mode:
|
||||||
|
region_info = get_geo_region_info("none")
|
||||||
|
geo_region = "none"
|
||||||
|
else:
|
||||||
|
region_info = get_geo_region_info(geo_region)
|
||||||
|
|
||||||
min_ranges = MIN_RANGES.get(geo_region, 1000)
|
min_ranges = MIN_RANGES.get(geo_region, 1000)
|
||||||
|
|
||||||
if os.path.isfile(backup_php):
|
if os.path.isfile(backup_php):
|
||||||
if not silent:
|
if not silent:
|
||||||
print(f"⚠️ GeoIP-Blocking bereits aktiv für {shop}")
|
print(f"⚠️ Blocking bereits aktiv für {shop}")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
if not os.path.isfile(index_php):
|
if not os.path.isfile(index_php):
|
||||||
@@ -673,14 +826,17 @@ def activate_blocking(shop, silent=False, mode="php+crowdsec", geo_region="dach"
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
if not silent:
|
if not silent:
|
||||||
print(f"\n🔧 Aktiviere {region_info['icon']} {region_info['name']} GeoIP-Blocking für: {shop}")
|
print(f"\n🔧 Aktiviere {region_info['icon']} {region_info['name']} für: {shop}")
|
||||||
print(f" Erlaubt: {region_info['description']}")
|
if is_bot_mode:
|
||||||
print(f" Modus: {'PHP + CrowdSec' if mode == 'php+crowdsec' else 'Nur PHP'}")
|
print(f" Modus: Nur Bot-Blocking (weltweit erreichbar)")
|
||||||
|
else:
|
||||||
|
print(f" Erlaubt: {region_info['description']}")
|
||||||
|
print(f" CrowdSec: {'Ja' if uses_crowdsec(mode) else 'Nein'}")
|
||||||
print("=" * 60)
|
print("=" * 60)
|
||||||
|
|
||||||
# Step 1: Watcher service
|
# Step 1: Watcher service
|
||||||
if mode == "php+crowdsec":
|
if uses_crowdsec(mode):
|
||||||
crowdsec_shops = [s for s in get_active_shops() if get_shop_mode(s) == "php+crowdsec"]
|
crowdsec_shops = [s for s in get_active_shops() if uses_crowdsec(get_shop_mode(s))]
|
||||||
if not crowdsec_shops and check_crowdsec():
|
if not crowdsec_shops and check_crowdsec():
|
||||||
if not silent:
|
if not silent:
|
||||||
print("\n[1/4] Installiere CrowdSec-Watcher-Service...")
|
print("\n[1/4] Installiere CrowdSec-Watcher-Service...")
|
||||||
@@ -688,7 +844,7 @@ def activate_blocking(shop, silent=False, mode="php+crowdsec", geo_region="dach"
|
|||||||
elif not silent:
|
elif not silent:
|
||||||
print("\n[1/4] CrowdSec-Watcher-Service bereits aktiv")
|
print("\n[1/4] CrowdSec-Watcher-Service bereits aktiv")
|
||||||
elif not silent:
|
elif not silent:
|
||||||
print("\n[1/4] CrowdSec-Synchronisation deaktiviert (nur PHP-Modus)")
|
print("\n[1/4] CrowdSec-Synchronisation deaktiviert")
|
||||||
|
|
||||||
# Step 2: PHP blocking
|
# Step 2: PHP blocking
|
||||||
if not silent:
|
if not silent:
|
||||||
@@ -715,40 +871,61 @@ def activate_blocking(shop, silent=False, mode="php+crowdsec", geo_region="dach"
|
|||||||
f.write('\n'.join(lines))
|
f.write('\n'.join(lines))
|
||||||
|
|
||||||
expiry = datetime.now() + timedelta(hours=72)
|
expiry = datetime.now() + timedelta(hours=72)
|
||||||
countries_array = generate_php_countries_array(geo_region)
|
|
||||||
|
|
||||||
template = GEOIP_SCRIPT_TEMPLATE if mode == "php+crowdsec" else GEOIP_SCRIPT_TEMPLATE_PHP_ONLY
|
# Select appropriate template
|
||||||
geoip_content = template.format(
|
if is_bot_mode:
|
||||||
region_name=region_info['name'],
|
if uses_crowdsec(mode):
|
||||||
region_description=region_info['description'],
|
template = BOT_ONLY_SCRIPT_TEMPLATE
|
||||||
expiry_date=expiry.strftime('%Y-%m-%d %H:%M:%S CET'),
|
else:
|
||||||
expiry_timestamp=expiry.strftime('%Y-%m-%d %H:%M:%S'),
|
template = BOT_ONLY_SCRIPT_TEMPLATE_NO_CROWDSEC
|
||||||
cache_file=CACHE_FILE,
|
|
||||||
log_file=LOG_FILE,
|
geoip_content = template.format(
|
||||||
crowdsec_queue=CROWDSEC_QUEUE_FILE,
|
expiry_date=expiry.strftime('%Y-%m-%d %H:%M:%S CET'),
|
||||||
shop_name=shop,
|
expiry_timestamp=expiry.strftime('%Y-%m-%d %H:%M:%S'),
|
||||||
countries_array=countries_array,
|
log_file=LOG_FILE,
|
||||||
min_ranges=min_ranges
|
crowdsec_queue=CROWDSEC_QUEUE_FILE,
|
||||||
)
|
shop_name=shop,
|
||||||
|
bot_patterns=generate_php_bot_patterns()
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
countries_array = generate_php_countries_array(geo_region)
|
||||||
|
template = GEOIP_SCRIPT_TEMPLATE if uses_crowdsec(mode) else GEOIP_SCRIPT_TEMPLATE_PHP_ONLY
|
||||||
|
geoip_content = template.format(
|
||||||
|
region_name=region_info['name'],
|
||||||
|
region_description=region_info['description'],
|
||||||
|
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,
|
||||||
|
countries_array=countries_array,
|
||||||
|
min_ranges=min_ranges
|
||||||
|
)
|
||||||
|
|
||||||
with open(blocking_file, 'w', encoding='utf-8') as f:
|
with open(blocking_file, 'w', encoding='utf-8') as f:
|
||||||
f.write(geoip_content)
|
f.write(geoip_content)
|
||||||
if not silent:
|
if not silent:
|
||||||
print(" ✅ PHP-Blocking aktiviert")
|
print(" ✅ PHP-Blocking aktiviert")
|
||||||
|
|
||||||
# Step 3: Generate cache
|
# Step 3: Generate cache (only for GeoIP modes)
|
||||||
if not silent:
|
if is_bot_mode:
|
||||||
print(f"\n[3/4] Generiere IP-Range-Cache ({len(region_info['countries'])} Länder)...")
|
|
||||||
|
|
||||||
success, range_count, error = generate_and_validate_cache(httpdocs, geo_region)
|
|
||||||
|
|
||||||
if success:
|
|
||||||
if not silent:
|
if not silent:
|
||||||
print(f" ✅ Cache generiert: {range_count:,} IP-Ranges")
|
print(f"\n[3/4] Cache-Generierung nicht erforderlich (Bot-Only)")
|
||||||
|
range_count = 0
|
||||||
else:
|
else:
|
||||||
if not silent:
|
if not silent:
|
||||||
print(f" ⚠️ Cache-Generierung: {error}")
|
print(f"\n[3/4] Generiere IP-Range-Cache ({len(region_info['countries'])} Länder)...")
|
||||||
print(f" ℹ️ Fail-Open aktiv - Cache wird beim ersten Request neu generiert")
|
|
||||||
|
success, range_count, error = generate_and_validate_cache(httpdocs, geo_region)
|
||||||
|
|
||||||
|
if success:
|
||||||
|
if not silent:
|
||||||
|
print(f" ✅ Cache generiert: {range_count:,} IP-Ranges")
|
||||||
|
else:
|
||||||
|
if not silent:
|
||||||
|
print(f" ⚠️ Cache-Generierung: {error}")
|
||||||
|
print(f" ℹ️ Fail-Open aktiv - Cache wird beim ersten Request neu generiert")
|
||||||
|
|
||||||
# Step 4: Register
|
# Step 4: Register
|
||||||
if not silent:
|
if not silent:
|
||||||
@@ -757,11 +934,15 @@ def activate_blocking(shop, silent=False, mode="php+crowdsec", geo_region="dach"
|
|||||||
|
|
||||||
if not silent:
|
if not silent:
|
||||||
print("\n" + "=" * 60)
|
print("\n" + "=" * 60)
|
||||||
print(f"✅ {region_info['icon']} {region_info['name']} GeoIP-Blocking aktiviert")
|
print(f"✅ {region_info['icon']} {region_info['name']} aktiviert")
|
||||||
print(f" Shop: {shop}")
|
print(f" Shop: {shop}")
|
||||||
print(f" IP-Ranges: {range_count:,}")
|
print(f" Modus: {get_mode_description(mode)} {get_mode_icon(mode)}")
|
||||||
|
if not is_bot_mode:
|
||||||
|
print(f" IP-Ranges: {range_count:,}")
|
||||||
|
print(f" 🛡️ Fail-Open: Bei Cache-Fehlern wird Traffic durchgelassen")
|
||||||
|
else:
|
||||||
|
print(f" 🤖 {len(BOT_PATTERNS)} Bot-Patterns aktiv")
|
||||||
print(f" Gültig bis: {expiry.strftime('%Y-%m-%d %H:%M:%S CET')}")
|
print(f" Gültig bis: {expiry.strftime('%Y-%m-%d %H:%M:%S CET')}")
|
||||||
print(f" 🛡️ Fail-Open: Bei Cache-Fehlern wird Traffic durchgelassen")
|
|
||||||
print("=" * 60)
|
print("=" * 60)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
@@ -804,14 +985,14 @@ def deactivate_blocking(shop, silent=False):
|
|||||||
|
|
||||||
if not silent:
|
if not silent:
|
||||||
print("\n[3/4] CrowdSec-Decisions entfernen...")
|
print("\n[3/4] CrowdSec-Decisions entfernen...")
|
||||||
if shop_mode == "php+crowdsec" and check_crowdsec():
|
if uses_crowdsec(shop_mode) and check_crowdsec():
|
||||||
cleanup_crowdsec_decisions(shop)
|
cleanup_crowdsec_decisions(shop)
|
||||||
elif not silent:
|
elif not silent:
|
||||||
print(" ℹ️ Keine CrowdSec-Synchronisation aktiv")
|
print(" ℹ️ Keine CrowdSec-Synchronisation aktiv")
|
||||||
|
|
||||||
if not silent:
|
if not silent:
|
||||||
print("\n[4/4] Prüfe Watcher-Service...")
|
print("\n[4/4] Prüfe Watcher-Service...")
|
||||||
crowdsec_shops = [s for s in get_active_shops() if get_shop_mode(s) == "php+crowdsec"]
|
crowdsec_shops = [s for s in get_active_shops() if uses_crowdsec(get_shop_mode(s))]
|
||||||
if not crowdsec_shops:
|
if not crowdsec_shops:
|
||||||
uninstall_watcher_service()
|
uninstall_watcher_service()
|
||||||
elif not silent:
|
elif not silent:
|
||||||
@@ -819,7 +1000,7 @@ def deactivate_blocking(shop, silent=False):
|
|||||||
|
|
||||||
if not silent:
|
if not silent:
|
||||||
print("\n" + "=" * 60)
|
print("\n" + "=" * 60)
|
||||||
print(f"✅ GeoIP-Blocking deaktiviert für: {shop}")
|
print(f"✅ Blocking deaktiviert für: {shop}")
|
||||||
print("=" * 60)
|
print("=" * 60)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
@@ -833,18 +1014,25 @@ def activate_all_shops():
|
|||||||
return
|
return
|
||||||
|
|
||||||
print(f"\n{'=' * 60}")
|
print(f"\n{'=' * 60}")
|
||||||
print(f" GeoIP-Blocking für ALLE Shops aktivieren")
|
print(f" Blocking für ALLE Shops aktivieren")
|
||||||
print(f"{'=' * 60}")
|
print(f"{'=' * 60}")
|
||||||
print(f"\n📋 {len(available_shops)} Shop(s):")
|
print(f"\n📋 {len(available_shops)} Shop(s):")
|
||||||
for shop in available_shops:
|
for shop in available_shops:
|
||||||
print(format_shop_with_link11(shop, prefix=" • "))
|
print(format_shop_with_link11(shop, prefix=" • "))
|
||||||
|
|
||||||
geo_region = select_geo_region()
|
|
||||||
region_info = get_geo_region_info(geo_region)
|
|
||||||
mode = select_mode()
|
mode = select_mode()
|
||||||
|
is_bot_mode = is_bot_only_mode(mode)
|
||||||
|
|
||||||
print(f"\n⚠️ Region: {region_info['icon']} {region_info['name']}")
|
if is_bot_mode:
|
||||||
print(f" Modus: {'PHP + CrowdSec 🛡️' if mode == 'php+crowdsec' else 'Nur PHP 📝'}")
|
geo_region = "none"
|
||||||
|
region_info = get_geo_region_info("none")
|
||||||
|
else:
|
||||||
|
geo_region = select_geo_region()
|
||||||
|
region_info = get_geo_region_info(geo_region)
|
||||||
|
|
||||||
|
print(f"\n⚠️ Modus: {get_mode_description(mode)} {get_mode_icon(mode)}")
|
||||||
|
if not is_bot_mode:
|
||||||
|
print(f" Region: {region_info['icon']} {region_info['name']}")
|
||||||
|
|
||||||
if input(f"\nFortfahren? (ja/nein): ").strip().lower() not in ['ja', 'j', 'yes', 'y']:
|
if input(f"\nFortfahren? (ja/nein): ").strip().lower() not in ['ja', 'j', 'yes', 'y']:
|
||||||
print("\n❌ Abgebrochen")
|
print("\n❌ Abgebrochen")
|
||||||
@@ -852,8 +1040,8 @@ def activate_all_shops():
|
|||||||
|
|
||||||
print(f"\n{'=' * 60}")
|
print(f"\n{'=' * 60}")
|
||||||
|
|
||||||
if mode == "php+crowdsec" and check_crowdsec():
|
if uses_crowdsec(mode) and check_crowdsec():
|
||||||
if not [s for s in get_active_shops() if get_shop_mode(s) == "php+crowdsec"]:
|
if not [s for s in get_active_shops() if uses_crowdsec(get_shop_mode(s))]:
|
||||||
print("\n📦 Installiere CrowdSec-Watcher-Service...")
|
print("\n📦 Installiere CrowdSec-Watcher-Service...")
|
||||||
install_watcher_service()
|
install_watcher_service()
|
||||||
|
|
||||||
@@ -890,33 +1078,54 @@ def activate_all_shops():
|
|||||||
f.write('\n'.join(lines))
|
f.write('\n'.join(lines))
|
||||||
|
|
||||||
expiry = datetime.now() + timedelta(hours=72)
|
expiry = datetime.now() + timedelta(hours=72)
|
||||||
template = GEOIP_SCRIPT_TEMPLATE if mode == "php+crowdsec" else GEOIP_SCRIPT_TEMPLATE_PHP_ONLY
|
|
||||||
geoip_content = template.format(
|
if is_bot_mode:
|
||||||
region_name=region_info['name'],
|
if uses_crowdsec(mode):
|
||||||
region_description=region_info['description'],
|
template = BOT_ONLY_SCRIPT_TEMPLATE
|
||||||
expiry_date=expiry.strftime('%Y-%m-%d %H:%M:%S CET'),
|
else:
|
||||||
expiry_timestamp=expiry.strftime('%Y-%m-%d %H:%M:%S'),
|
template = BOT_ONLY_SCRIPT_TEMPLATE_NO_CROWDSEC
|
||||||
cache_file=CACHE_FILE,
|
|
||||||
log_file=LOG_FILE,
|
geoip_content = template.format(
|
||||||
crowdsec_queue=CROWDSEC_QUEUE_FILE,
|
expiry_date=expiry.strftime('%Y-%m-%d %H:%M:%S CET'),
|
||||||
shop_name=shop,
|
expiry_timestamp=expiry.strftime('%Y-%m-%d %H:%M:%S'),
|
||||||
countries_array=generate_php_countries_array(geo_region),
|
log_file=LOG_FILE,
|
||||||
min_ranges=MIN_RANGES.get(geo_region, 1000)
|
crowdsec_queue=CROWDSEC_QUEUE_FILE,
|
||||||
)
|
shop_name=shop,
|
||||||
|
bot_patterns=generate_php_bot_patterns()
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
template = GEOIP_SCRIPT_TEMPLATE if uses_crowdsec(mode) else GEOIP_SCRIPT_TEMPLATE_PHP_ONLY
|
||||||
|
geoip_content = template.format(
|
||||||
|
region_name=region_info['name'],
|
||||||
|
region_description=region_info['description'],
|
||||||
|
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,
|
||||||
|
countries_array=generate_php_countries_array(geo_region),
|
||||||
|
min_ranges=MIN_RANGES.get(geo_region, 1000)
|
||||||
|
)
|
||||||
|
|
||||||
with open(blocking_file, 'w', encoding='utf-8') as f:
|
with open(blocking_file, 'w', encoding='utf-8') as f:
|
||||||
f.write(geoip_content)
|
f.write(geoip_content)
|
||||||
|
|
||||||
print(f" ⏳ Cache generieren...")
|
if is_bot_mode:
|
||||||
cache_ok, count, _ = generate_and_validate_cache(httpdocs, geo_region)
|
add_shop_to_active(shop, mode, geo_region)
|
||||||
|
print(f" ✅ Aktiviert ({len(BOT_PATTERNS)} Bot-Patterns)")
|
||||||
|
else:
|
||||||
|
print(f" ⏳ Cache generieren...")
|
||||||
|
cache_ok, count, _ = generate_and_validate_cache(httpdocs, geo_region)
|
||||||
|
add_shop_to_active(shop, mode, geo_region)
|
||||||
|
print(f" ✅ Aktiviert ({count:,} Ranges)" if cache_ok else f" ⚠️ Aktiviert (Cache-Warnung)")
|
||||||
|
|
||||||
add_shop_to_active(shop, mode, geo_region)
|
|
||||||
print(f" ✅ Aktiviert ({count:,} Ranges)" if cache_ok else f" ⚠️ Aktiviert (Cache-Warnung)")
|
|
||||||
success_count += 1
|
success_count += 1
|
||||||
|
|
||||||
print(f"\n{'=' * 60}")
|
print(f"\n{'=' * 60}")
|
||||||
print(f" ✅ {success_count} Shop(s) aktiviert")
|
print(f" ✅ {success_count} Shop(s) aktiviert")
|
||||||
print(f" 🛡️ Fail-Open bei Cache-Fehlern aktiv")
|
if not is_bot_mode:
|
||||||
|
print(f" 🛡️ Fail-Open bei Cache-Fehlern aktiv")
|
||||||
print(f"{'=' * 60}")
|
print(f"{'=' * 60}")
|
||||||
|
|
||||||
|
|
||||||
@@ -928,12 +1137,13 @@ def deactivate_all_shops():
|
|||||||
return
|
return
|
||||||
|
|
||||||
print(f"\n{'=' * 60}")
|
print(f"\n{'=' * 60}")
|
||||||
print(f" GeoIP-Blocking für ALLE deaktivieren")
|
print(f" Blocking für ALLE deaktivieren")
|
||||||
print(f"{'=' * 60}")
|
print(f"{'=' * 60}")
|
||||||
print(f"\n📋 {len(active_shops)} Shop(s):")
|
print(f"\n📋 {len(active_shops)} Shop(s):")
|
||||||
for shop in active_shops:
|
for shop in active_shops:
|
||||||
region_info = get_geo_region_info(get_shop_geo_region(shop))
|
region_info = get_geo_region_info(get_shop_geo_region(shop))
|
||||||
print(f" • {format_shop_with_link11(shop)} {region_info['icon']}")
|
mode_icon = get_mode_icon(get_shop_mode(shop))
|
||||||
|
print(f" • {format_shop_with_link11(shop)} {region_info['icon']} {mode_icon}")
|
||||||
|
|
||||||
if input(f"\nFortfahren? (ja/nein): ").strip().lower() not in ['ja', 'j', 'yes', 'y']:
|
if input(f"\nFortfahren? (ja/nein): ").strip().lower() not in ['ja', 'j', 'yes', 'y']:
|
||||||
print("\n❌ Abgebrochen")
|
print("\n❌ Abgebrochen")
|
||||||
@@ -969,12 +1179,25 @@ def get_shop_log_stats(shop):
|
|||||||
log_file = os.path.join(httpdocs, LOG_FILE)
|
log_file = os.path.join(httpdocs, LOG_FILE)
|
||||||
php_blocks = 0
|
php_blocks = 0
|
||||||
ips = {}
|
ips = {}
|
||||||
|
bots = {} # Track bot statistics
|
||||||
|
|
||||||
|
shop_mode = get_shop_mode(shop)
|
||||||
|
is_bot_mode = is_bot_only_mode(shop_mode)
|
||||||
|
|
||||||
if os.path.isfile(log_file):
|
if os.path.isfile(log_file):
|
||||||
with open(log_file, 'r') as f:
|
with open(log_file, 'r') as f:
|
||||||
for line in f:
|
for line in f:
|
||||||
php_blocks += 1
|
php_blocks += 1
|
||||||
ip, ua = None, 'Unknown'
|
ip, ua = None, 'Unknown'
|
||||||
|
detected_bot = None
|
||||||
|
|
||||||
|
# Parse bot-only format: BOT: botname | IP: ...
|
||||||
|
if 'BOT: ' in line:
|
||||||
|
try:
|
||||||
|
detected_bot = line.split('BOT: ')[1].split(' |')[0].strip()
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
if 'IP: ' in line:
|
if 'IP: ' in line:
|
||||||
try:
|
try:
|
||||||
ip = line.split('IP: ')[1].split(' |')[0].strip()
|
ip = line.split('IP: ')[1].split(' |')[0].strip()
|
||||||
@@ -985,6 +1208,7 @@ def get_shop_log_stats(shop):
|
|||||||
ua = line.split('UA: ')[1].split(' |')[0].strip()
|
ua = line.split('UA: ')[1].split(' |')[0].strip()
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
if ip:
|
if ip:
|
||||||
if ip not in ips:
|
if ip not in ips:
|
||||||
ips[ip] = {'count': 0, 'ua': ua}
|
ips[ip] = {'count': 0, 'ua': ua}
|
||||||
@@ -992,7 +1216,15 @@ def get_shop_log_stats(shop):
|
|||||||
if ua != 'Unknown' and ips[ip]['ua'] == 'Unknown':
|
if ua != 'Unknown' and ips[ip]['ua'] == 'Unknown':
|
||||||
ips[ip]['ua'] = ua
|
ips[ip]['ua'] = ua
|
||||||
|
|
||||||
return php_blocks, ips, get_shop_activation_time(shop)
|
# Track bot statistics
|
||||||
|
if detected_bot:
|
||||||
|
bots[detected_bot] = bots.get(detected_bot, 0) + 1
|
||||||
|
elif ua and ua != 'Unknown':
|
||||||
|
bot_name = detect_bot(ua)
|
||||||
|
if bot_name != 'Unbekannt':
|
||||||
|
bots[bot_name] = bots.get(bot_name, 0) + 1
|
||||||
|
|
||||||
|
return php_blocks, ips, bots, get_shop_activation_time(shop)
|
||||||
|
|
||||||
|
|
||||||
def show_logs(shop):
|
def show_logs(shop):
|
||||||
@@ -1001,8 +1233,9 @@ def show_logs(shop):
|
|||||||
shop_mode = get_shop_mode(shop)
|
shop_mode = get_shop_mode(shop)
|
||||||
shop_geo = get_shop_geo_region(shop)
|
shop_geo = get_shop_geo_region(shop)
|
||||||
region_info = get_geo_region_info(shop_geo)
|
region_info = get_geo_region_info(shop_geo)
|
||||||
|
is_bot_mode = is_bot_only_mode(shop_mode)
|
||||||
|
|
||||||
blocks, ips, activation_time = get_shop_log_stats(shop)
|
blocks, ips, bots, activation_time = get_shop_log_stats(shop)
|
||||||
|
|
||||||
if activation_time:
|
if activation_time:
|
||||||
runtime = (datetime.now() - activation_time).total_seconds() / 60
|
runtime = (datetime.now() - activation_time).total_seconds() / 60
|
||||||
@@ -1011,13 +1244,23 @@ def show_logs(shop):
|
|||||||
runtime, req_min = 0, 0
|
runtime, req_min = 0, 0
|
||||||
|
|
||||||
print(f"\n{'═' * 70}")
|
print(f"\n{'═' * 70}")
|
||||||
print(f"📊 {shop} | {region_info['icon']} {region_info['name']}")
|
print(f"📊 {shop} | {region_info['icon']} {region_info['name']} {get_mode_icon(shop_mode)}")
|
||||||
print(f"{'═' * 70}")
|
print(f"{'═' * 70}")
|
||||||
print(f"⏱️ Laufzeit: {format_duration(runtime)}")
|
print(f"⏱️ Laufzeit: {format_duration(runtime)}")
|
||||||
print(f"📈 Blocks: {blocks} ({req_min:.1f} req/min)")
|
print(f"📈 Blocks: {blocks} ({req_min:.1f} req/min)")
|
||||||
|
|
||||||
valid, count, err = validate_existing_cache(httpdocs, shop_geo)
|
if not is_bot_mode:
|
||||||
print(f"✅ Cache: {count:,} Ranges" if valid else f"⚠️ Cache: {err}")
|
valid, count, err = validate_existing_cache(httpdocs, shop_geo)
|
||||||
|
print(f"✅ Cache: {count:,} Ranges" if valid else f"⚠️ Cache: {err}")
|
||||||
|
else:
|
||||||
|
print(f"🤖 Bot-Patterns: {len(BOT_PATTERNS)} aktiv")
|
||||||
|
|
||||||
|
# Show bot statistics for bot-only mode
|
||||||
|
if bots:
|
||||||
|
print(f"\n🤖 Bot-Statistik:")
|
||||||
|
for bot_name, count in sorted(bots.items(), key=lambda x: x[1], reverse=True)[:10]:
|
||||||
|
bar = "█" * min(count // 5, 20) if count > 0 else "█"
|
||||||
|
print(f" {bot_name}: {count}x {bar}")
|
||||||
|
|
||||||
if os.path.isfile(log_file):
|
if os.path.isfile(log_file):
|
||||||
print(f"\n📝 Letzte 30 Blocks:")
|
print(f"\n📝 Letzte 30 Blocks:")
|
||||||
@@ -1046,13 +1289,14 @@ def show_all_logs():
|
|||||||
print(f" {COLOR_GREEN}Grün = hinter Link11{COLOR_RESET} | {COLOR_RED}Rot = Direkt{COLOR_RESET}")
|
print(f" {COLOR_GREEN}Grün = hinter Link11{COLOR_RESET} | {COLOR_RED}Rot = Direkt{COLOR_RESET}")
|
||||||
|
|
||||||
total_php_blocks = 0
|
total_php_blocks = 0
|
||||||
shop_php_stats = {} # shop -> {'blocks': N, 'runtime_minutes': float, 'req_min': float, 'ips': {}}
|
shop_php_stats = {} # shop -> {'blocks': N, 'runtime_minutes': float, 'req_min': float, 'ips': {}, 'bots': {}}
|
||||||
all_ips = {} # ip -> {'count': N, 'ua': user_agent, 'shops': {shop: count}}
|
all_ips = {} # ip -> {'count': N, 'ua': user_agent, 'shops': {shop: count}}
|
||||||
|
all_bots = {} # bot_name -> count
|
||||||
total_minutes = 0
|
total_minutes = 0
|
||||||
|
|
||||||
# Collect PHP stats
|
# Collect PHP stats
|
||||||
for shop in active_shops:
|
for shop in active_shops:
|
||||||
blocks, ips, activation_time = get_shop_log_stats(shop)
|
blocks, ips, bots, activation_time = get_shop_log_stats(shop)
|
||||||
total_php_blocks += blocks
|
total_php_blocks += blocks
|
||||||
|
|
||||||
# Calculate runtime and req/min
|
# Calculate runtime and req/min
|
||||||
@@ -1067,7 +1311,8 @@ def show_all_logs():
|
|||||||
'blocks': blocks,
|
'blocks': blocks,
|
||||||
'runtime_minutes': runtime_minutes,
|
'runtime_minutes': runtime_minutes,
|
||||||
'req_min': req_min,
|
'req_min': req_min,
|
||||||
'ips': ips
|
'ips': ips,
|
||||||
|
'bots': bots
|
||||||
}
|
}
|
||||||
|
|
||||||
if runtime_minutes > total_minutes:
|
if runtime_minutes > total_minutes:
|
||||||
@@ -1081,6 +1326,9 @@ def show_all_logs():
|
|||||||
if data['ua'] != 'Unknown' and all_ips[ip]['ua'] == 'Unknown':
|
if data['ua'] != 'Unknown' and all_ips[ip]['ua'] == 'Unknown':
|
||||||
all_ips[ip]['ua'] = data['ua']
|
all_ips[ip]['ua'] = data['ua']
|
||||||
|
|
||||||
|
for bot_name, count in bots.items():
|
||||||
|
all_bots[bot_name] = all_bots.get(bot_name, 0) + count
|
||||||
|
|
||||||
# Calculate total req/min
|
# Calculate total req/min
|
||||||
total_req_min = total_php_blocks / total_minutes if total_minutes > 0 else 0
|
total_req_min = total_php_blocks / total_minutes if total_minutes > 0 else 0
|
||||||
|
|
||||||
@@ -1097,7 +1345,7 @@ def show_all_logs():
|
|||||||
total_crowdsec = sum(crowdsec_stats.values())
|
total_crowdsec = sum(crowdsec_stats.values())
|
||||||
|
|
||||||
# Display PHP blocks with req/min and top IP per shop
|
# 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)})")
|
print(f"\n📝 Blocks gesamt: {total_php_blocks} (⌀ {total_req_min:.1f} req/min, Laufzeit: {format_duration(total_minutes)})")
|
||||||
if shop_php_stats:
|
if shop_php_stats:
|
||||||
for shop in sorted(shop_php_stats.keys()):
|
for shop in sorted(shop_php_stats.keys()):
|
||||||
stats = shop_php_stats[shop]
|
stats = shop_php_stats[shop]
|
||||||
@@ -1107,10 +1355,11 @@ def show_all_logs():
|
|||||||
bar = "█" * min(int(req_min * 2), 20) if req_min > 0 else ""
|
bar = "█" * min(int(req_min * 2), 20) if req_min > 0 else ""
|
||||||
runtime_str = format_duration(runtime) if runtime > 0 else "?"
|
runtime_str = format_duration(runtime) if runtime > 0 else "?"
|
||||||
|
|
||||||
# Get geo region icon
|
# Get geo region icon and mode icon
|
||||||
geo_region = get_shop_geo_region(shop)
|
geo_region = get_shop_geo_region(shop)
|
||||||
region_info = get_geo_region_info(geo_region)
|
region_info = get_geo_region_info(geo_region)
|
||||||
geo_icon = region_info['icon']
|
geo_icon = region_info['icon']
|
||||||
|
mode_icon = get_mode_icon(get_shop_mode(shop))
|
||||||
|
|
||||||
# Color shop name based on Link11 status
|
# Color shop name based on Link11 status
|
||||||
link11_info = check_link11(shop)
|
link11_info = check_link11(shop)
|
||||||
@@ -1119,7 +1368,7 @@ def show_all_logs():
|
|||||||
else:
|
else:
|
||||||
shop_colored = f"{COLOR_RED}{shop}{COLOR_RESET}"
|
shop_colored = f"{COLOR_RED}{shop}{COLOR_RESET}"
|
||||||
|
|
||||||
print(f" ├─ {shop_colored} {geo_icon}: {count} ({req_min:.1f} req/min, seit {runtime_str}) {bar}")
|
print(f" ├─ {shop_colored} {geo_icon} {mode_icon}: {count} ({req_min:.1f} req/min, seit {runtime_str}) {bar}")
|
||||||
|
|
||||||
# Show top IP for this shop
|
# Show top IP for this shop
|
||||||
shop_ips = stats['ips']
|
shop_ips = stats['ips']
|
||||||
@@ -1148,6 +1397,7 @@ def show_all_logs():
|
|||||||
geo_region = get_shop_geo_region(shop)
|
geo_region = get_shop_geo_region(shop)
|
||||||
region_info = get_geo_region_info(geo_region)
|
region_info = get_geo_region_info(geo_region)
|
||||||
geo_icon = region_info['icon']
|
geo_icon = region_info['icon']
|
||||||
|
mode_icon = get_mode_icon(get_shop_mode(shop))
|
||||||
|
|
||||||
link11_info = check_link11(shop)
|
link11_info = check_link11(shop)
|
||||||
if link11_info['is_link11']:
|
if link11_info['is_link11']:
|
||||||
@@ -1155,12 +1405,19 @@ def show_all_logs():
|
|||||||
else:
|
else:
|
||||||
shop_colored = f"{COLOR_RED}{shop}{COLOR_RESET}"
|
shop_colored = f"{COLOR_RED}{shop}{COLOR_RESET}"
|
||||||
|
|
||||||
print(f" ├─ {shop_colored} {geo_icon}: {count} {bar}")
|
print(f" ├─ {shop_colored} {geo_icon} {mode_icon}: {count} {bar}")
|
||||||
elif check_crowdsec():
|
elif check_crowdsec():
|
||||||
print(" └─ Keine aktiven Bans")
|
print(" └─ Keine aktiven Bans")
|
||||||
else:
|
else:
|
||||||
print(" └─ CrowdSec nicht verfügbar")
|
print(" └─ CrowdSec nicht verfügbar")
|
||||||
|
|
||||||
|
# Display bot statistics
|
||||||
|
if all_bots:
|
||||||
|
print(f"\n🤖 Bot-Statistik (alle Shops):")
|
||||||
|
for bot_name, count in sorted(all_bots.items(), key=lambda x: x[1], reverse=True)[:15]:
|
||||||
|
bar = "█" * min(count // 5, 20) if count > 0 else "█"
|
||||||
|
print(f" {bot_name}: {count}x {bar}")
|
||||||
|
|
||||||
# Top 50 blocked IPs with bot detection, req/min, and top shop
|
# Top 50 blocked IPs with bot detection, req/min, and top shop
|
||||||
if all_ips:
|
if all_ips:
|
||||||
print(f"\n🔥 Top 50 blockierte IPs (alle Shops):")
|
print(f"\n🔥 Top 50 blockierte IPs (alle Shops):")
|
||||||
@@ -1209,8 +1466,8 @@ def show_all_logs():
|
|||||||
|
|
||||||
def main():
|
def main():
|
||||||
print("\n" + "=" * 60)
|
print("\n" + "=" * 60)
|
||||||
print(" GeoIP Shop Blocker Manager v3.1.0")
|
print(" GeoIP Shop Blocker Manager v3.2.0")
|
||||||
print(" 🇩🇪🇦🇹🇨🇭 DACH | 🇪🇺 Eurozone+GB (22 Länder)")
|
print(" 🇩🇪🇦🇹🇨🇭 DACH | 🇪🇺 Eurozone+GB | 🤖 Bot-Only")
|
||||||
print(" 🛡️ Mit Cache-Validierung und Fail-Open")
|
print(" 🛡️ Mit Cache-Validierung und Fail-Open")
|
||||||
print("=" * 60)
|
print("=" * 60)
|
||||||
|
|
||||||
@@ -1243,10 +1500,18 @@ def main():
|
|||||||
try:
|
try:
|
||||||
idx = int(input("\nShop wählen: ").strip()) - 1
|
idx = int(input("\nShop wählen: ").strip()) - 1
|
||||||
if 0 <= idx < len(available):
|
if 0 <= idx < len(available):
|
||||||
geo = select_geo_region()
|
|
||||||
mode = select_mode()
|
mode = select_mode()
|
||||||
region_info = get_geo_region_info(geo)
|
is_bot_mode = is_bot_only_mode(mode)
|
||||||
if input(f"\n{region_info['icon']} aktivieren für '{available[idx]}'? (ja/nein): ").lower() in ['ja', 'j']:
|
|
||||||
|
if is_bot_mode:
|
||||||
|
geo = "none"
|
||||||
|
region_info = get_geo_region_info("none")
|
||||||
|
else:
|
||||||
|
geo = select_geo_region()
|
||||||
|
region_info = get_geo_region_info(geo)
|
||||||
|
|
||||||
|
confirm_msg = f"\n{region_info['icon']} {get_mode_description(mode)} aktivieren für '{available[idx]}'? (ja/nein): "
|
||||||
|
if input(confirm_msg).lower() in ['ja', 'j']:
|
||||||
activate_blocking(available[idx], mode=mode, geo_region=geo)
|
activate_blocking(available[idx], mode=mode, geo_region=geo)
|
||||||
except:
|
except:
|
||||||
print("❌ Ungültig")
|
print("❌ Ungültig")
|
||||||
@@ -1259,7 +1524,7 @@ def main():
|
|||||||
print("\n📋 Aktive Shops:")
|
print("\n📋 Aktive Shops:")
|
||||||
for i, shop in enumerate(active, 1):
|
for i, shop in enumerate(active, 1):
|
||||||
region_info = get_geo_region_info(get_shop_geo_region(shop))
|
region_info = get_geo_region_info(get_shop_geo_region(shop))
|
||||||
mode_icon = "🛡️" if get_shop_mode(shop) == "php+crowdsec" else "📝"
|
mode_icon = get_mode_icon(get_shop_mode(shop))
|
||||||
print(f" [{i}] {format_shop_with_link11(shop)} {region_info['icon']} {mode_icon}")
|
print(f" [{i}] {format_shop_with_link11(shop)} {region_info['icon']} {mode_icon}")
|
||||||
try:
|
try:
|
||||||
idx = int(input("\nShop wählen: ").strip()) - 1
|
idx = int(input("\nShop wählen: ").strip()) - 1
|
||||||
@@ -1278,7 +1543,8 @@ def main():
|
|||||||
print(" [0] 📊 ALLE")
|
print(" [0] 📊 ALLE")
|
||||||
for i, shop in enumerate(active, 1):
|
for i, shop in enumerate(active, 1):
|
||||||
region_info = get_geo_region_info(get_shop_geo_region(shop))
|
region_info = get_geo_region_info(get_shop_geo_region(shop))
|
||||||
print(f" [{i}] {format_shop_with_link11(shop)} {region_info['icon']}")
|
mode_icon = get_mode_icon(get_shop_mode(shop))
|
||||||
|
print(f" [{i}] {format_shop_with_link11(shop)} {region_info['icon']} {mode_icon}")
|
||||||
try:
|
try:
|
||||||
idx = int(input("\nWähle: ").strip())
|
idx = int(input("\nWähle: ").strip())
|
||||||
if idx == 0:
|
if idx == 0:
|
||||||
@@ -1294,16 +1560,22 @@ def main():
|
|||||||
print(f"\n📊 {len(active)}/{len(shops)} Shops aktiv")
|
print(f"\n📊 {len(active)}/{len(shops)} Shops aktiv")
|
||||||
for shop in active:
|
for shop in active:
|
||||||
region_info = get_geo_region_info(get_shop_geo_region(shop))
|
region_info = get_geo_region_info(get_shop_geo_region(shop))
|
||||||
mode_icon = "🛡️" if get_shop_mode(shop) == "php+crowdsec" else "📝"
|
shop_mode = get_shop_mode(shop)
|
||||||
blocks, _, activation_time = get_shop_log_stats(shop)
|
mode_icon = get_mode_icon(shop_mode)
|
||||||
|
is_bot_mode = is_bot_only_mode(shop_mode)
|
||||||
|
blocks, _, bots, activation_time = get_shop_log_stats(shop)
|
||||||
runtime = (datetime.now() - activation_time).total_seconds() / 60 if activation_time else 0
|
runtime = (datetime.now() - activation_time).total_seconds() / 60 if activation_time else 0
|
||||||
|
|
||||||
httpdocs = os.path.join(VHOSTS_DIR, shop, 'httpdocs')
|
httpdocs = os.path.join(VHOSTS_DIR, shop, 'httpdocs')
|
||||||
valid, count, _ = validate_existing_cache(httpdocs, get_shop_geo_region(shop))
|
|
||||||
cache_str = f"✅{count:,}" if valid else "⚠️"
|
|
||||||
|
|
||||||
print(f" {format_shop_with_link11(shop)} {region_info['icon']} {mode_icon}")
|
print(f" {format_shop_with_link11(shop)} {region_info['icon']} {mode_icon}")
|
||||||
print(f" {blocks} blocks, {format_duration(runtime)}, Cache: {cache_str}")
|
|
||||||
|
if is_bot_mode:
|
||||||
|
print(f" {blocks} blocks, {format_duration(runtime)}, {len(BOT_PATTERNS)} Bot-Patterns")
|
||||||
|
else:
|
||||||
|
valid, count, _ = validate_existing_cache(httpdocs, get_shop_geo_region(shop))
|
||||||
|
cache_str = f"✅{count:,}" if valid else "⚠️"
|
||||||
|
print(f" {blocks} blocks, {format_duration(runtime)}, Cache: {cache_str}")
|
||||||
|
|
||||||
elif choice == "5":
|
elif choice == "5":
|
||||||
activate_all_shops()
|
activate_all_shops()
|
||||||
|
|||||||
Reference in New Issue
Block a user