diff --git a/SUMMARY.md b/SUMMARY.md index 93085aed..ecf494cb 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -10,6 +10,8 @@ Die MYP-Plattform (My Young Printer) ist ein Verwaltungssystem für 3D-Drucker m - Offline-Fähigkeit durch Service Worker Integration - REST-API für Frontend und externe Dienste - Automatisierte Auftrags-Planung und -Ausführung via Scheduler +- Verschlüsselte Kommunikation über HTTPS mit selbstsignierten Zertifikaten +- Kiosk-Modus für Informationsdisplays und öffentliche Terminals Das Backend basiert auf Flask (Python) und nutzt eine SQLite-Datenbank für die Datenspeicherung. @@ -24,22 +26,40 @@ Die MYP-Plattform setzt auf eine verteilte Netzwerk-Architektur: - **3D-Drucker**: Werden als Netzwerkgeräte mit festen IP-Adressen konfiguriert - **Frontend**: Als Web-App mit Offline-Funktionalität konzipiert - **PWA-Funktionalität**: Service Worker für Offline-Betrieb und Cache-Management +- **Kiosk-Displays**: Raspberry Pi mit Chrome im Kiosk-Modus ### Netzwerk-Topologie ``` -[Frontend/PWA] <-- HTTP/REST --> [Flask-Backend] <-- PyP110-Lib --> [Smart-Plugs] - ^ ^ | - | | v - +------ PWA Offline Cache -------+ [3D-Drucker] + ┌──────────────────┐ + │ Command Center │ + │ (192.168.0.1) │ + └──────────┬───────┘ + │ + ▼ +┌───────────────┐ ┌─────────────────────┐ ┌──────────────┐ +│ Frontend/PWA │◄────►│ Flask-Backend │◄────►│ Smart-Plugs │ +│(192.168.0.105)│ │ (192.168.0.105) │ │(192.168.0.1xx)│ +└───────┬───────┘ └─────────┬───────────┘ └──────┬────────┘ + │ │ │ + │ │ ▼ +┌───────▼───────┐ │ ┌────────────────┐ +│ Kiosk-Mode │ │ │ 3D-Drucker │ +│ (10.0.0.1-10) │ │ │(192.168.0.1xx) │ +└───────────────┘ ▼ └────────────────┘ + ┌─────────────────────┐ + │ Ad-hoc Pi-Netzwerk │ + │ (10.0.0.x/24) │ + └─────────────────────┘ ``` ### Kommunikationsprotokolle -- **HTTP/REST**: Zwischen Frontend und Backend +- **HTTPS/REST**: Zwischen Frontend und Backend (Port 5000) - **JSON**: Standardformat für Datenaustausch - **Tapo-Protokoll**: Für Smart-Plug-Steuerung via PyP110-Bibliothek - **SQLite**: Lokale Datenbankanbindung +- **TLS 1.2/1.3**: Verschlüsselte Kommunikation mit selbstsignierten Zertifikaten ### Vernetzungs-Features @@ -47,6 +67,8 @@ Die MYP-Plattform setzt auf eine verteilte Netzwerk-Architektur: - SmartPlug-Integration für Fernsteuerung der Stromversorgung - Offline-Betriebsmodus mit synchronisierenden Service Workern - Automatische Erkennung der Drucker-Status via Netzwerk-Polling +- Kiosk-Modus mit automatischem Start nach Systemneustart +- Command Center für zentrale Verwaltung aller Komponenten ## 3. Hauptkomponenten des Backends @@ -64,6 +86,7 @@ Das Backend stellt eine umfassende REST-API bereit: - **Printer Management**: Druckerstatus, Steuerung - **Job Management**: Auftragsplanung, -verwaltung und -überwachung - **Stats API**: Statistiken und Auswertungen +- **Kiosk API**: Steuerung der Kiosk-Displays ### SmartPlug-Integration @@ -71,6 +94,13 @@ Das Backend stellt eine umfassende REST-API bereit: - Automatisierte Steuerung der Stromversorgung basierend auf Jobplanung - Status-Monitoring und Fehlerbehandlung +### SSL/HTTPS-Implementierung + +- Selbstsignierte Zertifikate für verschlüsselte Kommunikation +- Automatische Zertifikatsgenerierung während der Installation +- Konfigurierbare Zertifikatslaufzeit (Standard: 10 Jahre) +- Prüfwerkzeuge für Zertifikatsstatus und -gültigkeit + ## 4. Datenbankmodell & Scheduler-Logik ### Datenbankmodelle @@ -111,6 +141,9 @@ Der BackgroundTaskScheduler bietet: | /api/scheduler/status | GET | Scheduler-Status | Ja | | /api/scheduler/start | POST | Scheduler starten | Ja, Admin | | /api/scheduler/stop | POST | Scheduler stoppen | Ja, Admin | +| /api/kiosk/status | GET | Kiosk-Status | Ja | +| /api/kiosk/activate | POST | Kiosk aktivieren | Ja, Admin | +| /api/kiosk/deactivate | POST | Kiosk deaktivieren | Ja, Admin | | /auth/login | POST | Anmelden | Nein | | /auth/logout | GET/POST | Abmelden | Ja | @@ -125,6 +158,7 @@ Der BackgroundTaskScheduler bietet: ### Netzwerksicherheit +- HTTPS mit selbstsignierten TLS-Zertifikaten - CORS-Konfiguration für sichere Cross-Origin-Requests - Sicherheitsheader im Response (X-Content-Type-Options, X-Frame-Options) - Keine sensiblen Daten in URLs oder Query-Parametern @@ -137,17 +171,57 @@ Der BackgroundTaskScheduler bietet: ## 7. Build- & Deployment-Ablauf +### Installationsprozess + +Die Installation der MYP-Plattform erfolgt über verschiedene Shell-Skripte: + +- **setup_myp.sh**: Hauptinstallationsskript (Command Center) + - Standardinstallation mit HTTPS-Unterstützung + - Kiosk-Modus-Installation (gehärtete Variante) + - Netzwerk- und DNS-Konfiguration + - Systemüberwachung und Logging + +- **create_ssl_cert.sh**: Generiert selbstsignierte Zertifikate + - Unterstützt Multiple-SAN-Entries (Hostname, IP-Adressen) + - Konfigurierbare Zertifikatslaufzeit + - Automatische Fehlerbehandlung + +- **ssl_check.sh**: Prüft SSL-Zertifikatsstatus + - Validiert Gültigkeitsdauer + - Zeigt Fingerprint und Subject-Details + - Warnt vor bald ablaufenden Zertifikaten + ### Backend-Deployment - Python 3.11 venv-Umgebung - Konfigurierbare Entwicklungs- und Produktionsumgebungen - Log-Rotation und strukturierte Logging-Hierarchie +- SSL/TLS-Unterstützung mit automatischer Zertifikatsgenerierung + +### Kiosk-Modus + +- Basiert auf Raspberry Pi mit Chromium Browser +- Automatischer Start im Vollbildmodus nach Boot +- Deaktivierung von Fehlerdialogen und Warnungen +- Integrierte Überwachung und Watchdog-Funktionalität +- Spezielle Konfiguration für öffentliche Informationsdisplays +- Ignoriert SSL-Zertifikatswarnungen für selbstsignierte Zertifikate + +### Command Center + +- Zentrales Verwaltungstool mit CLI-Interface +- Integrierte Systemdiagnose und -überwachung +- Einfache Verwaltung von SSL-Zertifikaten +- Fernsteuerung von Kiosk-Displays +- Netzwerk- und IP-Konfiguration +- Dienst-Management (Start/Stop/Neustart) ### Frontend-Integration - Tailwind CSS für responsive UI - CLI-Befehle für Tailwind-Kompilierung - Service Worker für PWA-Funktionalität +- HTTPS-Unterstützung mit Proxy-Konfiguration ### Systemd-Integration @@ -169,6 +243,7 @@ Der BackgroundTaskScheduler bietet: - OAuth2-Integration für externe Authentifizierungsquellen - Zwei-Faktor-Authentifizierung - Zertifikatsbasierte Geräteauthentifizierung für SmartPlugs +- Letsencrypt-Integration für vertrauenswürdige Zertifikate ### Skalierbarkeit diff --git a/backend/app/app.py b/backend/app/app.py index def51193..1d811075 100644 --- a/backend/app/app.py +++ b/backend/app/app.py @@ -18,7 +18,7 @@ from flask_wtf.csrf import CSRFProtect from config.settings import ( SECRET_KEY, TAPO_USERNAME, TAPO_PASSWORD, PRINTERS, FLASK_HOST, FLASK_PORT, FLASK_DEBUG, SESSION_LIFETIME, - SCHEDULER_INTERVAL, SCHEDULER_ENABLED + SCHEDULER_INTERVAL, SCHEDULER_ENABLED, get_ssl_context ) from utils.logging_config import setup_logging, get_logger, log_startup_info from models import User, Printer, Job, Stats, get_db_session, init_database, create_initial_admin @@ -1265,16 +1265,19 @@ def tailwind_watch(): # Auto-Kompilierung beim Serverstart im Debug-Modus def compile_tailwind_if_debug(): - if app.debug: + """Kompiliert Tailwind CSS im Debug-Modus, falls notwendig.""" + if FLASK_DEBUG: try: - subprocess.run(["npx", "tailwindcss", "-i", "./static/css/input.css", - "-o", "./static/css/tailwind-dark-consolidated.min.css"], - check=True, capture_output=True) - print("Tailwind CSS für Debug-Modus kompiliert.") - except subprocess.CalledProcessError as e: - print(f"Warnung: Konnte Tailwind CSS nicht kompilieren: {e}") - except FileNotFoundError: - print("Warnung: Node.js/npm nicht gefunden. Tailwind CSS wurde nicht kompiliert.") + app_logger.info("Kompiliere Tailwind CSS...") + subprocess.run([ + "npx", "tailwindcss", "-i", "static/css/input.css", + "-o", "static/css/tailwind.min.css", "--minify" + ], check=True) + app_logger.info("Tailwind CSS erfolgreich kompiliert.") + except subprocess.CalledProcessError: + app_logger.warning("Tailwind konnte nicht kompiliert werden. Möglicherweise ist npx/Node.js nicht installiert.") + except Exception as e: + app_logger.error(f"Fehler beim Kompilieren von Tailwind CSS: {str(e)}") # Tailwind CSS kompilieren, wenn im Debug-Modus if FLASK_DEBUG: @@ -1282,34 +1285,65 @@ if FLASK_DEBUG: # Initialisierung der Datenbank beim Start def init_app(): + """Initialisiert die App-Komponenten und startet den Scheduler.""" + # Datenbank initialisieren try: - # Datenbank initialisieren init_database() - # Admin-Benutzer erstellen oder zurücksetzen create_initial_admin() - - # Template-Helper registrieren - register_template_helpers(app) - app_logger.info("Template-Helper registriert") - - # Scheduler starten, wenn aktiviert - if SCHEDULER_ENABLED: - scheduler.start() - app_logger.info("Job-Scheduler gestartet") except Exception as e: - app_logger.error(f"Fehler bei der Initialisierung: {str(e)}") + app_logger.error(f"Fehler bei der Datenbank-Initialisierung: {str(e)}") + + # Jinja2-Helfer registrieren + register_template_helpers(app) + + # Tailwind im Debug-Modus kompilieren + compile_tailwind_if_debug() + + # Scheduler starten, wenn aktiviert + if SCHEDULER_ENABLED: + try: + # Scheduler-Task für Druckauftrags-Prüfung registrieren + scheduler.register_task( + "check_jobs", + check_jobs, + interval=SCHEDULER_INTERVAL + ) + + # Scheduler starten + scheduler.start() + app_logger.info(f"Scheduler gestartet mit Intervall {SCHEDULER_INTERVAL} Sekunden.") + except Exception as e: + app_logger.error(f"Fehler beim Starten des Schedulers: {str(e)}") + + # SSL-Kontext protokollieren + ssl_context = get_ssl_context() + if ssl_context: + app_logger.info(f"SSL aktiviert mit Zertifikat {ssl_context[0]}") + else: + app_logger.warning("SSL ist deaktiviert. Die Verbindung ist unverschlüsselt!") # App starten if __name__ == "__main__": - # Initialisierung ausführen - init_app() - - # Flask-Server starten - app.run( - host=FLASK_HOST, - port=FLASK_PORT, - debug=FLASK_DEBUG - ) + try: + # App initialisieren + init_app() + + # SSL-Kontext ermitteln + ssl_context = get_ssl_context() + + # Konsolen-Ausgabe für HTTPS + protocol = "HTTPS" if ssl_context else "HTTP" + app_logger.info(f"MYP startet auf {protocol}://{FLASK_HOST}:{FLASK_PORT} (Debug: {FLASK_DEBUG})") + + # App starten + app.run( + host=FLASK_HOST, + port=FLASK_PORT, + debug=FLASK_DEBUG, + ssl_context=ssl_context + ) + except Exception as e: + app_logger.critical(f"Kritischer Fehler beim Starten der Anwendung: {str(e)}") # Content Security Policy anpassen @app.after_request diff --git a/backend/app/config/settings.py b/backend/app/config/settings.py index beb65ef1..f4571615 100644 --- a/backend/app/config/settings.py +++ b/backend/app/config/settings.py @@ -31,6 +31,11 @@ FLASK_PORT = 5000 FLASK_DEBUG = True SESSION_LIFETIME = timedelta(days=7) +# SSL-Konfiguration +SSL_ENABLED = True +SSL_CERT_PATH = "/opt/myp/ssl/myp.crt" +SSL_KEY_PATH = "/opt/myp/ssl/myp.key" + # Scheduler-Konfiguration SCHEDULER_INTERVAL = 60 # Sekunden SCHEDULER_ENABLED = True @@ -63,4 +68,47 @@ def ensure_database_directory(): """Erstellt das Datenbank-Verzeichnis.""" db_dir = os.path.dirname(DATABASE_PATH) if db_dir: - os.makedirs(db_dir, exist_ok=True) \ No newline at end of file + os.makedirs(db_dir, exist_ok=True) + +def ensure_ssl_directory(): + """Erstellt das SSL-Verzeichnis, falls es nicht existiert.""" + ssl_dir = os.path.dirname(SSL_CERT_PATH) + if ssl_dir and not os.path.exists(ssl_dir): + os.makedirs(ssl_dir, exist_ok=True) + +def get_ssl_context(): + """ + Gibt den SSL-Kontext für Flask zurück, wenn SSL aktiviert ist. + + Returns: + tuple oder None: Tuple mit Zertifikat- und Schlüsselpfad, wenn SSL aktiviert ist, sonst None + """ + if not SSL_ENABLED: + return None + + # Wenn Zertifikate nicht existieren, diese automatisch erstellen + if not os.path.exists(SSL_CERT_PATH) or not os.path.exists(SSL_KEY_PATH): + ensure_ssl_directory() + + # Prüfen, ob wir uns im Entwicklungsmodus befinden + if FLASK_DEBUG: + print("SSL-Zertifikate nicht gefunden. Erstelle selbstsignierte Zertifikate...") + + # Pfad zum create_ssl_cert.sh-Skript ermitteln + script_path = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))), + "install", "create_ssl_cert.sh") + + # Ausführungsrechte setzen + if os.path.exists(script_path): + os.system(f"chmod +x {script_path}") + + # Zertifikate erstellen + os.system(f"{script_path} -c {SSL_CERT_PATH} -k {SSL_KEY_PATH}") + else: + print(f"WARNUNG: SSL-Zertifikat-Generator nicht gefunden: {script_path}") + return None + else: + print("WARNUNG: SSL-Zertifikate nicht gefunden und Nicht-Debug-Modus. SSL wird deaktiviert.") + return None + + return (SSL_CERT_PATH, SSL_KEY_PATH) \ No newline at end of file diff --git a/backend/app/static/js/sw.js b/backend/app/static/js/sw.js index 57692ea3..e95026a9 100644 --- a/backend/app/static/js/sw.js +++ b/backend/app/static/js/sw.js @@ -87,7 +87,7 @@ self.addEventListener('fetch', (event) => { const { request } = event; const url = new URL(request.url); - // Skip non-GET requests and unsupported schemes for caching + // Unterstütze sowohl HTTP als auch HTTPS if (request.method !== 'GET' || (url.protocol !== 'http:' && url.protocol !== 'https:')) { return; diff --git a/backend/install/create_ssl_cert.sh b/backend/install/create_ssl_cert.sh new file mode 100755 index 00000000..a30e8b85 --- /dev/null +++ b/backend/install/create_ssl_cert.sh @@ -0,0 +1,160 @@ +#!/usr/bin/env bash +# MYP V2 - SSL-Zertifikat-Generator +# Erstellt selbstsignierte Zertifikate für die HTTPS-Kommunikation + +# Fehlerabbruch aktivieren +set -e + +# Farben für bessere Lesbarkeit +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[0;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +# Funktion für Titel +print_header() { + echo -e "${BLUE}================================================================${NC}" + echo -e "${BLUE} MYP V2 - SSL-Zertifikat-Generator ${NC}" + echo -e "${BLUE}================================================================${NC}" + echo "" +} + +# Standardwerte +CERT_DIR="/opt/myp/ssl" +CERT_FILE="$CERT_DIR/myp.crt" +KEY_FILE="$CERT_DIR/myp.key" +DAYS_VALID=3650 # 10 Jahre +HOSTNAME=$(hostname -f) +IP_ADDRESS=$(hostname -I | awk '{print $1}') + +# Hilfe-Funktion +show_help() { + echo "Verwendung: $0 [Optionen]" + echo "" + echo "Optionen:" + echo " -d, --dir DIR Verzeichnis für Zertifikate (Standard: $CERT_DIR)" + echo " -c, --cert DATEI Pfad zur Zertifikatsdatei (Standard: $CERT_FILE)" + echo " -k, --key DATEI Pfad zur Schlüsseldatei (Standard: $KEY_FILE)" + echo " -h, --hostname NAME Hostname für das Zertifikat (Standard: $HOSTNAME)" + echo " -i, --ip IP IP-Adresse für das Zertifikat (Standard: $IP_ADDRESS)" + echo " -v, --valid TAGE Gültigkeitsdauer in Tagen (Standard: $DAYS_VALID)" + echo " --help Diese Hilfe anzeigen" + echo "" +} + +# Argumente verarbeiten +while [[ $# -gt 0 ]]; do + case $1 in + -d|--dir) + CERT_DIR="$2" + shift 2 + ;; + -c|--cert) + CERT_FILE="$2" + shift 2 + ;; + -k|--key) + KEY_FILE="$2" + shift 2 + ;; + -h|--hostname) + HOSTNAME="$2" + shift 2 + ;; + -i|--ip) + IP_ADDRESS="$2" + shift 2 + ;; + -v|--valid) + DAYS_VALID="$2" + shift 2 + ;; + --help) + show_help + exit 0 + ;; + *) + echo -e "${RED}Unbekannte Option: $1${NC}" + show_help + exit 1 + ;; + esac +done + +# Header anzeigen +print_header + +# Verzeichnis erstellen, falls es nicht existiert +if [ ! -d "$CERT_DIR" ]; then + echo -e "${YELLOW}Erstelle Verzeichnis $CERT_DIR...${NC}" + mkdir -p "$CERT_DIR" +fi + +# Überprüfen, ob openssl installiert ist +if ! command -v openssl &> /dev/null; then + echo -e "${RED}OpenSSL ist nicht installiert!${NC}" + echo -e "${YELLOW}Installiere OpenSSL...${NC}" + apt-get update && apt-get install -y openssl +fi + +# Zertifikat erstellen +echo -e "${GREEN}Erstelle selbstsigniertes SSL-Zertifikat...${NC}" +echo -e "${BLUE}Hostname: ${NC}$HOSTNAME" +echo -e "${BLUE}IP-Adresse: ${NC}$IP_ADDRESS" +echo -e "${BLUE}Gültigkeitsdauer: ${NC}$DAYS_VALID Tage" +echo -e "${BLUE}Zertifikatsdatei: ${NC}$CERT_FILE" +echo -e "${BLUE}Schlüsseldatei: ${NC}$KEY_FILE" +echo "" + +# OpenSSL-Konfiguration erstellen +CONFIG_FILE="$CERT_DIR/openssl.cnf" +cat > "$CONFIG_FILE" << EOF +[req] +default_bits = 2048 +prompt = no +default_md = sha256 +distinguished_name = req_distinguished_name +x509_extensions = v3_req + +[req_distinguished_name] +C = DE +ST = Baden-Wuerttemberg +L = Stuttgart +O = Mercedes-Benz AG +OU = MYP Platform +CN = $HOSTNAME + +[v3_req] +keyUsage = critical, digitalSignature, keyAgreement +extendedKeyUsage = serverAuth +subjectAltName = @alt_names + +[alt_names] +DNS.1 = $HOSTNAME +DNS.2 = localhost +IP.1 = $IP_ADDRESS +IP.2 = 127.0.0.1 +EOF + +# Schlüssel und Zertifikat generieren +openssl req -x509 -nodes -days "$DAYS_VALID" -newkey rsa:2048 \ + -keyout "$KEY_FILE" -out "$CERT_FILE" \ + -config "$CONFIG_FILE" + +# Berechtigungen setzen +chmod 600 "$KEY_FILE" +chmod 644 "$CERT_FILE" + +echo "" +echo -e "${GREEN}SSL-Zertifikat erfolgreich erstellt!${NC}" +echo -e "${YELLOW}Fingerprint:${NC}" +openssl x509 -noout -fingerprint -sha256 -in "$CERT_FILE" +echo "" +echo -e "${BLUE}Um diese Zertifikate mit Flask zu verwenden:${NC}" +echo " 1. Importiere die SSL-Einstellungen in der app.py" +echo " 2. Starte Flask mit SSL-Unterstützung" +echo "" +echo -e "${YELLOW}Beispiel:${NC}" +echo " app.run(host='0.0.0.0', port=5000, ssl_context=('$CERT_FILE', '$KEY_FILE'))" +echo "" \ No newline at end of file diff --git a/backend/install/kiosk.sh b/backend/install/kiosk.sh index 96baf297..c82a7ebf 100755 --- a/backend/install/kiosk.sh +++ b/backend/install/kiosk.sh @@ -14,6 +14,11 @@ sed -i 's/"exited_cleanly":false/"exited_cleanly":true/' \ sed -i 's/"exit_type":"Crashed"/"exit_type":"Normal"/' \ "$HOME/.config/chromium/Default/Preferences" 2>/dev/null || true -# Browser starten +# Hostname und IP ermitteln +HOSTNAME=$(hostname -f) +IP_ADDRESS=$(hostname -I | awk '{print $1}') + +# Browser starten mit SSL-Warnung deaktiviert chromium-browser --kiosk --noerrdialogs --disable-infobars \ - --window-position=0,0 --app=http://localhost:5000/ & \ No newline at end of file + --window-position=0,0 --ignore-certificate-errors \ + --app=https://${IP_ADDRESS}:5000/ & \ No newline at end of file diff --git a/backend/install/ssl_check.sh b/backend/install/ssl_check.sh new file mode 100755 index 00000000..8f7a21b2 --- /dev/null +++ b/backend/install/ssl_check.sh @@ -0,0 +1,99 @@ +#!/usr/bin/env bash +# MYP SSL-Zertifikat-Prüfskript +# Prüft den Status der SSL-Zertifikate und gibt Informationen aus + +# Fehlerabbruch aktivieren +set -e + +# Farben für bessere Lesbarkeit +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[0;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +# Standardwerte +CERT_PATH="/opt/myp/ssl/myp.crt" +KEY_PATH="/opt/myp/ssl/myp.key" + +# Argumente verarbeiten +while [[ $# -gt 0 ]]; do + case $1 in + -c|--cert) + CERT_PATH="$2" + shift 2 + ;; + -k|--key) + KEY_PATH="$2" + shift 2 + ;; + *) + echo -e "${RED}Unbekannte Option: $1${NC}" + exit 1 + ;; + esac +done + +# Header anzeigen +echo -e "${BLUE}================================================================${NC}" +echo -e "${BLUE} MYP V2 - SSL-Zertifikat-Statusprüfung ${NC}" +echo -e "${BLUE}================================================================${NC}" +echo "" + +# Prüfen, ob OpenSSL installiert ist +if ! command -v openssl &> /dev/null; then + echo -e "${RED}OpenSSL ist nicht installiert!${NC}" + exit 1 +fi + +# Prüfen, ob Zertifikat existiert +if [ ! -f "$CERT_PATH" ]; then + echo -e "${RED}Zertifikat nicht gefunden: $CERT_PATH${NC}" + echo -e "${YELLOW}Führen Sie 'create_ssl_cert.sh' aus, um ein neues Zertifikat zu erstellen.${NC}" + exit 1 +fi + +# Prüfen, ob Schlüssel existiert +if [ ! -f "$KEY_PATH" ]; then + echo -e "${RED}Schlüssel nicht gefunden: $KEY_PATH${NC}" + echo -e "${YELLOW}Führen Sie 'create_ssl_cert.sh' aus, um einen neuen Schlüssel zu erstellen.${NC}" + exit 1 +fi + +# Zertifikatsinformationen anzeigen +echo -e "${GREEN}Zertifikatsinformationen:${NC}" +echo -e "${BLUE}Zertifikatsdatei: ${NC}$CERT_PATH" +echo -e "${BLUE}Schlüsseldatei: ${NC}$KEY_PATH" +echo "" + +# Zertifikatsdetails anzeigen +echo -e "${YELLOW}Zertifikatsdetails:${NC}" +openssl x509 -in "$CERT_PATH" -noout -subject -issuer -dates -fingerprint -sha256 + +# Gültigkeit prüfen +echo "" +echo -e "${YELLOW}Gültigkeitsprüfung:${NC}" +not_after=$(openssl x509 -in "$CERT_PATH" -noout -enddate | cut -d= -f2) +not_after_seconds=$(date -d "$not_after" +%s) +now_seconds=$(date +%s) +days_left=$(( (not_after_seconds - now_seconds) / 86400 )) + +if [ $days_left -le 0 ]; then + echo -e "${RED}Zertifikat ist ABGELAUFEN!${NC}" +elif [ $days_left -le 30 ]; then + echo -e "${YELLOW}Zertifikat läuft in $days_left Tagen ab!${NC}" +else + echo -e "${GREEN}Zertifikat ist noch $days_left Tage gültig.${NC}" +fi + +# Zertifikatsinhalte prüfen +echo "" +echo -e "${YELLOW}Zertifikatsinhalte:${NC}" +echo -e "${BLUE}Alternative Namen (SAN):${NC}" +openssl x509 -in "$CERT_PATH" -noout -text | grep -A1 "Subject Alternative Name" + +# Abschluss +echo "" +echo -e "${GREEN}SSL-Prüfung abgeschlossen.${NC}" +echo -e "${BLUE}Um die Zertifikate zu erneuern, führen Sie 'create_ssl_cert.sh' aus.${NC}" +echo "" \ No newline at end of file diff --git a/backend/setup_myp.sh b/backend/setup_myp.sh index d5e9976e..4c193723 100755 --- a/backend/setup_myp.sh +++ b/backend/setup_myp.sh @@ -61,6 +61,7 @@ show_main_menu() { echo "7) MYP-Dienst starten/stoppen/neustarten" echo "8) Logs anzeigen" echo "9) Dokumentation anzeigen" + echo "10) SSL-Zertifikat-Management" echo "" echo "q) Beenden" echo "" @@ -98,6 +99,9 @@ process_main_menu() { 9) show_documentation ;; + 10) + show_ssl_management + ;; q|Q) echo -e "${GREEN}Auf Wiedersehen!${NC}" exit 0 @@ -131,7 +135,7 @@ standard_installation() { echo "Installiere System-Abhängigkeiten..." apt update apt install -y python3.11 python3.11-pip python3.11-venv python3.11-dev \ - build-essential git curl + build-essential git curl openssl # Verzeichnis für MYP erstellen/aktualisieren mkdir -p /opt/myp @@ -156,6 +160,9 @@ standard_installation() { # Datenbank-Verzeichnis erstellen mkdir -p /opt/myp/data + # SSL-Verzeichnis erstellen + mkdir -p /opt/myp/ssl + # Python-Umgebung und Abhängigkeiten einrichten echo "Richte Python-Umgebung ein..." cd /opt/myp @@ -166,12 +173,18 @@ standard_installation() { pip install --upgrade pip pip install -r requirements.txt + # SSL-Zertifikate erstellen + echo "Erstelle SSL-Zertifikate..." + chmod +x /opt/myp/install/create_ssl_cert.sh + /opt/myp/install/create_ssl_cert.sh -d /opt/myp/ssl + # Berechtigungen setzen echo "Setze Berechtigungen..." chown -R www-data:www-data /opt/myp chmod -R 755 /opt/myp chmod -R 775 /opt/myp/logs chmod -R 775 /opt/myp/data + chmod 600 /opt/myp/ssl/myp.key echo -e "${GREEN}Installation abgeschlossen.${NC}" echo "" @@ -181,6 +194,7 @@ standard_installation() { echo " cd /opt/myp && source .venv/bin/activate && python3.11 app/app.py" echo "" echo -e "${BLUE}Oder verwenden Sie Option 7 für Dienst-Management${NC}" + echo -e "${GREEN}MYP V2 ist unter https://$(hostname -I | awk '{print $1}'):5000 erreichbar${NC}" read -p "Drücken Sie eine Taste, um zum Hauptmenü zurückzukehren..." show_main_menu @@ -1267,40 +1281,61 @@ system_status() { echo -e "${GREEN}System-Status${NC}" echo "" - # MYP-Status + # Systeminfos anzeigen + echo -e "${YELLOW}Systeminformationen:${NC}" + echo -e "Hostname: $(hostname)" + echo -e "IP-Adresse: $(hostname -I | awk '{print $1}')" + echo -e "Betriebssystem: $(lsb_release -ds 2>/dev/null || cat /etc/*release 2>/dev/null | head -n1 || uname -om)" + echo -e "Kernel: $(uname -r)" + echo -e "CPU: $(grep -c ^processor /proc/cpuinfo) Kerne" + echo -e "RAM: $(free -h | awk '/^Mem/ {print $2}')" + echo -e "Festplatte: $(df -h / | awk 'NR==2 {print $2}')" + echo "" + + # MYP-Status anzeigen echo -e "${YELLOW}MYP-Status:${NC}" if is_myp_installed; then - echo "MYP ist installiert in /opt/myp" - if systemctl is-active --quiet myp.service; then - echo -e "MYP-Dienst: ${GREEN}Aktiv${NC}" + echo -e "MYP ist installiert: ${GREEN}Ja${NC}" + + # Prüfen, ob der MYP-Service läuft + if systemctl is-active --quiet myp.service 2>/dev/null; then + echo -e "MYP-Service: ${GREEN}Aktiv${NC}" else - echo -e "MYP-Dienst: ${RED}Inaktiv${NC}" + echo -e "MYP-Service: ${RED}Inaktiv${NC}" fi + + # Pfadangaben + echo -e "Installationspfad: /opt/myp" + echo -e "Datenbank: /opt/myp/data" + echo -e "Logs: /opt/myp/logs" + echo -e "SSL-Zertifikate: /opt/myp/ssl" + + # SSL-Status überprüfen + if [ -f "/opt/myp/ssl/myp.crt" ] && [ -f "/opt/myp/ssl/myp.key" ]; then + echo -e "SSL-Zertifikate: ${GREEN}Vorhanden${NC}" + + # Zertifikatsinformationen anzeigen + if command -v openssl &> /dev/null; then + cert_expiry=$(openssl x509 -enddate -noout -in /opt/myp/ssl/myp.crt | cut -d= -f 2) + cert_subject=$(openssl x509 -subject -noout -in /opt/myp/ssl/myp.crt | sed 's/^subject=//') + echo -e "Zertifikat für: ${BLUE}$cert_subject${NC}" + echo -e "Gültig bis: ${BLUE}$cert_expiry${NC}" + fi + else + echo -e "SSL-Zertifikate: ${RED}Fehlen${NC}" + fi + + # MYP-URLs anzeigen + echo -e "" + echo -e "${YELLOW}MYP-Zugriff:${NC}" + ip_address=$(hostname -I | awk '{print $1}') + echo -e "${GREEN}https://$ip_address:5000${NC} (verschlüsselt)" + echo -e "${YELLOW}http://$ip_address:5000${NC} (unverschlüsselt)" else - echo -e "MYP ist ${RED}nicht installiert${NC}" + echo -e "MYP ist installiert: ${RED}Nein${NC}" fi - echo "" - # Netzwerkstatus - echo -e "${YELLOW}Netzwerkstatus:${NC}" - ip -o addr show | awk '$3 == "inet" {print $2 ": " $4}' echo "" - - # DNS-Server - echo -e "${YELLOW}DNS-Server:${NC}" - grep "nameserver" /etc/resolv.conf 2>/dev/null || echo "Keine DNS-Server konfiguriert." - echo "" - - # Systemressourcen - echo -e "${YELLOW}Systemressourcen:${NC}" - echo "CPU-Auslastung:" - top -bn1 | grep "Cpu(s)" | awk '{print $2 + $4 "% genutzt"}' - echo "Speichernutzung:" - free -h | grep "Mem:" | awk '{print $3 " von " $2 " genutzt"}' - echo "Festplattenbelegung:" - df -h / | grep -v "Filesystem" | awk '{print $3 " von " $2 " genutzt (" $5 ")"}' - echo "" - read -p "Drücken Sie eine Taste, um zum Hauptmenü zurückzukehren..." show_main_menu } @@ -1491,6 +1526,57 @@ show_documentation() { show_main_menu } +# 10) SSL-Zertifikat-Management +show_ssl_management() { + print_header + echo -e "${GREEN}SSL-Zertifikat-Management${NC}" + echo "" + + echo -e "Bitte wählen Sie eine Option:" + echo "" + echo "1) SSL-Zertifikatsstatus anzeigen" + echo "2) Neue SSL-Zertifikate erstellen" + echo "3) SSL-Einstellungen in settings.py anzeigen/bearbeiten" + echo "" + echo "b) Zurück zum Hauptmenü" + echo "" + read -p "Ihre Auswahl: " ssl_option + + case $ssl_option in + 1) + # SSL-Status anzeigen + chmod +x /opt/myp/install/ssl_check.sh + /opt/myp/install/ssl_check.sh + ;; + 2) + # Neue Zertifikate erstellen + echo -e "${YELLOW}Erstelle neue SSL-Zertifikate...${NC}" + chmod +x /opt/myp/install/create_ssl_cert.sh + /opt/myp/install/create_ssl_cert.sh -d /opt/myp/ssl + ;; + 3) + # SSL-Einstellungen anzeigen/bearbeiten + if command -v nano &> /dev/null; then + nano /opt/myp/app/config/settings.py + else + vi /opt/myp/app/config/settings.py + fi + ;; + b|B) + show_main_menu + return + ;; + *) + echo -e "${RED}Ungültige Option.${NC}" + sleep 2 + show_ssl_management + ;; + esac + + read -p "Drücken Sie eine Taste, um zum SSL-Menü zurückzukehren..." + show_ssl_management +} + # Hauptprogramm check_root show_main_menu \ No newline at end of file diff --git a/frontend/next.config.mjs b/frontend/next.config.mjs index a53ad9fa..5f40b97c 100644 --- a/frontend/next.config.mjs +++ b/frontend/next.config.mjs @@ -27,12 +27,12 @@ const nextConfig = { return [ { source: '/api/backend/:path*', - destination: 'http://192.168.0.105:5000/api/:path*', + destination: 'https://192.168.0.105:5000/api/:path*', }, // Direkter Proxy für Health-Checks { source: '/backend-health', - destination: 'http://192.168.0.105:5000/health', + destination: 'https://192.168.0.105:5000/health', }, ]; }, diff --git a/frontend/src/app/layout.tsx b/frontend/src/app/layout.tsx index 06d5c381..d62883f2 100644 --- a/frontend/src/app/layout.tsx +++ b/frontend/src/app/layout.tsx @@ -1,6 +1,7 @@ import { Header } from "@/components/header"; import { Toaster } from "@/components/ui/toaster"; import type { Metadata } from "next"; +import { SSLWarning } from "@/components/ui/ssl-warning"; import "@/app/globals.css"; @@ -26,6 +27,7 @@ export default function RootLayout(props: RootLayoutProps) {
SSL-Sicherheitshinweis
++ Diese Anwendung verwendet ein selbstsigniertes SSL-Zertifikat für sichere Kommunikation. + Um Verbindungsprobleme zu vermeiden, öffnen Sie bitte einmalig die folgende URL und akzeptieren Sie das Zertifikat: +
+ +