diff --git a/AppImage/components/secure-gateway-setup.tsx b/AppImage/components/secure-gateway-setup.tsx index c6fc8057..02d99ef3 100644 --- a/AppImage/components/secure-gateway-setup.tsx +++ b/AppImage/components/secure-gateway-setup.tsx @@ -1204,41 +1204,47 @@ export function SecureGatewaySetup() { } } }}> - - - - - Secure Gateway Setup - - + + {/* Fixed Header */} +
+ + + + Secure Gateway Setup + + - {/* Progress indicator - filter out "options" step if using Proxmox Only */} -
- {wizardSteps - .filter((step) => !(config.access_mode === "host_only" && step.id === "options")) - .map((step, idx) => { - // Recalculate the actual step index accounting for skipped steps - const actualIdx = wizardSteps.findIndex((s) => s.id === step.id) - const adjustedCurrentStep = config.access_mode === "host_only" - ? (currentStep > wizardSteps.findIndex((s) => s.id === "options") ? currentStep - 1 : currentStep) - : currentStep - return ( -
- ) - })} + {/* Progress indicator - filter out "options" step if using Proxmox Only */} +
+ {wizardSteps + .filter((step) => !(config.access_mode === "host_only" && step.id === "options")) + .map((step, idx) => { + // Recalculate the actual step index accounting for skipped steps + const actualIdx = wizardSteps.findIndex((s) => s.id === step.id) + const adjustedCurrentStep = config.access_mode === "host_only" + ? (currentStep > wizardSteps.findIndex((s) => s.id === "options") ? currentStep - 1 : currentStep) + : currentStep + return ( +
+ ) + })} +
- {renderWizardContent()} + {/* Scrollable Content */} +
+ {renderWizardContent()} +
- {/* Navigation */} -
+ {/* Fixed Footer with Navigation */} +
+ + {/* Delete button separated with divider to prevent accidental clicks */} +
-
@@ -3802,26 +3804,34 @@ ${(report.sections && report.sections.length > 0) ? `
- {/* Report tabs */} -
+ {/* Report tabs - responsive with shorter labels on mobile */} +
{(["overview", "checks", "warnings", "suggestions"] as const).map((tab) => ( ))}
diff --git a/AppImage/scripts/notification_events.py b/AppImage/scripts/notification_events.py index 39cdf376..622589e4 100644 --- a/AppImage/scripts/notification_events.py +++ b/AppImage/scripts/notification_events.py @@ -403,13 +403,30 @@ class JournalWatcher: def _check_fail2ban(self, msg: str, syslog_id: str): """Detect Fail2Ban IP bans.""" - if 'fail2ban' not in msg.lower() and syslog_id != 'fail2ban-server': - return + # Only process actual fail2ban action messages, not systemd service events + if syslog_id not in ('fail2ban-server', 'fail2ban.actions', 'fail2ban'): + if 'fail2ban' not in msg.lower(): + return + # Skip systemd service lifecycle messages (start/stop/restart/reload) + msg_lower = msg.lower() + if any(x in msg_lower for x in ['service', 'started', 'stopped', 'starting', + 'stopping', 'reloading', 'reloaded', 'unit', + 'deactivated', 'activated']): + return - # Ban detected - ban_match = re.search(r'Ban\s+(\S+)', msg) + # Ban detected - match only valid IPv4 or IPv6 addresses + # IPv4: 192.168.1.100, IPv6: 2001:db8::1 or ::ffff:192.168.1.1 + ban_match = re.search(r'Ban\s+((?:\d{1,3}\.){3}\d{1,3}|[0-9a-fA-F:]{2,})', msg) if ban_match: ip = ban_match.group(1) + # Validate it's a real IP address format + # IPv4: must have 4 octets separated by dots + # IPv6: must contain at least one colon + is_ipv4 = re.match(r'^(\d{1,3}\.){3}\d{1,3}$', ip) + is_ipv6 = ':' in ip and re.match(r'^[0-9a-fA-F:]+$', ip) + if not is_ipv4 and not is_ipv6: + return # Not a valid IP (e.g., "Service.", "Ban", etc.) + jail_match = re.search(r'\[(\w+)\]', msg) jail = jail_match.group(1) if jail_match else 'unknown' diff --git a/AppImage/scripts/notification_templates.py b/AppImage/scripts/notification_templates.py index c87b595b..86c2cef2 100644 --- a/AppImage/scripts/notification_templates.py +++ b/AppImage/scripts/notification_templates.py @@ -1384,7 +1384,7 @@ AI_DETAIL_TOKENS = { # System prompt template - optimized hybrid version AI_SYSTEM_PROMPT = """You are a notification FORMATTER for ProxMenux Monitor (Proxmox VE). -Your job: translate and reformat alerts into {language}. You are NOT an analyst ��� do not interpret or diagnose. +Your job: translate and reformat alerts into {language}. You are NOT an analyst — do not interpret or diagnose. ═══ WHAT TO TRANSLATE ═══ Translate: labels, descriptions, status words, units (GB→Go in French, etc.) diff --git a/AppImage/scripts/startup_grace.py b/AppImage/scripts/startup_grace.py index 405b1bb4..33a92df8 100644 --- a/AppImage/scripts/startup_grace.py +++ b/AppImage/scripts/startup_grace.py @@ -21,7 +21,7 @@ import time import threading from typing import Set, List, Tuple, Optional -# ─── Configuration ──────────────────────────────────��──────────────────────── +# ─── Configuration ─────────────────────────────────────────────────────────── # Grace period durations (seconds) STARTUP_VM_GRACE_SECONDS = 180 # 3 minutes for VM/CT start aggregation diff --git a/scripts/menus/main_menu.sh b/scripts/menus/main_menu.sh index c9d8f41b..ee6f96d9 100644 --- a/scripts/menus/main_menu.sh +++ b/scripts/menus/main_menu.sh @@ -94,7 +94,7 @@ show_menu() { dialog --clear \ --backtitle "ProxMenux" \ --title "$(translate "$menu_title")" \ - --menu "$(translate "Select an option:")" 20 70 10 \ + --menu "$(translate "Select an option:")" 20 70 11 \ 1 "$(translate "Settings post-install Proxmox")" \ 2 "$(translate "Hardware: GPUs and Coral-TPU")" \ 3 "$(translate "Create VM from template or script")" \ @@ -102,7 +102,8 @@ show_menu() { 5 "$(translate "Mount and Share Manager")" \ 6 "$(translate "Proxmox VE Helper Scripts")" \ 7 "$(translate "Network Management")" \ - 8 "$(translate "Utilities and Tools")" \ + 8 "$(translate "Security")" \ + 9 "$(translate "Utilities and Tools")" \ h "$(translate "Help and Info Commands")" \ s "$(translate "Settings")" \ 0 "$(translate "Exit")" 2>"$TEMP_FILE" @@ -126,7 +127,8 @@ show_menu() { 5) exec bash "$LOCAL_SCRIPTS/menus/share_menu.sh" ;; 6) exec bash "$LOCAL_SCRIPTS/menus/menu_Helper_Scripts.sh" ;; 7) exec bash "$LOCAL_SCRIPTS/menus/network_menu.sh" ;; - 8) exec bash "$LOCAL_SCRIPTS/menus/utilities_menu.sh" ;; + 8) exec bash "$LOCAL_SCRIPTS/menus/security_menu.sh" ;; + 9) exec bash "$LOCAL_SCRIPTS/menus/utilities_menu.sh" ;; h) bash "$LOCAL_SCRIPTS/help_info_menu.sh" ;; s) exec bash "$LOCAL_SCRIPTS/menus/config_menu.sh" ;; 0) clear; msg_ok "$(translate "Thank you for using ProxMenux. Goodbye!")"; rm -f "$TEMP_FILE"; exit 0 ;;