"Update installer scripts for SSL integration (feat)"

This commit is contained in:
Till Tomczak 2025-05-26 11:03:15 +02:00
parent 6896ba291f
commit e93f3906e1
2 changed files with 763 additions and 503 deletions

View File

@ -1 +1,518 @@
# MYP Installer Control Center
# Zentrale Installationskonsole für die MYP-Plattform
# Kombiniert Setup-Funktionen für SSL, Hosts, Docker und mehr
# Farbdefinitionen für bessere Lesbarkeit
$colors = @{
Title = "Cyan"
Success = "Green"
Error = "Red"
Warning = "Yellow"
Info = "Blue"
Command = "White"
}
# Überprüfen, ob das Skript als Administrator ausgeführt wird
$isAdmin = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
function Show-Header {
param ([string]$Title)
Clear-Host
Write-Host "=============================================================" -ForegroundColor $colors.Title
Write-Host " MYP INSTALLER CONTROL CENTER" -ForegroundColor $colors.Title
Write-Host "=============================================================" -ForegroundColor $colors.Title
Write-Host " $Title" -ForegroundColor $colors.Title
Write-Host "=============================================================" -ForegroundColor $colors.Title
if (-not $isAdmin) {
Write-Host "HINWEIS: Dieses Skript läuft ohne Administrator-Rechte." -ForegroundColor $colors.Warning
Write-Host "Einige Funktionen sind möglicherweise eingeschränkt." -ForegroundColor $colors.Warning
Write-Host "=============================================================" -ForegroundColor $colors.Title
}
Write-Host ""
}
function Test-Command {
param ([string]$Command)
try {
Get-Command $Command -ErrorAction Stop | Out-Null
return $true
} catch {
return $false
}
}
function Exec-Command {
param (
[string]$Command,
[string]$Description
)
Write-Host "> $Description..." -ForegroundColor $colors.Info
try {
Invoke-Expression $Command | Out-Host
if ($LASTEXITCODE -eq 0 -or $null -eq $LASTEXITCODE) {
Write-Host "✓ Erfolgreich abgeschlossen!" -ForegroundColor $colors.Success
return $true
} else {
Write-Host "✗ Fehler beim Ausführen des Befehls. Exit-Code: $LASTEXITCODE" -ForegroundColor $colors.Error
return $false
}
} catch {
Write-Host "✗ Fehler: $_" -ForegroundColor $colors.Error
return $false
}
}
function Get-LocalIPAddress {
$localIP = (Get-NetIPAddress | Where-Object { $_.AddressFamily -eq "IPv4" -and $_.PrefixOrigin -ne "WellKnown" } | Select-Object -First 1).IPAddress
if (-not $localIP) {
$localIP = "127.0.0.1"
}
return $localIP
}
function Test-Dependencies {
Write-Host "Prüfe Abhängigkeiten..." -ForegroundColor $colors.Info
$dependencies = @{
"python" = "Python (3.6+)"
"pip" = "Python Package Manager"
"docker" = "Docker"
"docker-compose" = "Docker Compose"
"node" = "Node.js"
"npm" = "Node Package Manager"
"openssl" = "OpenSSL"
}
$allInstalled = $true
foreach ($dep in $dependencies.GetEnumerator()) {
$installed = Test-Command $dep.Key
if ($installed) {
Write-Host "$($dep.Value) gefunden" -ForegroundColor $colors.Success
} else {
Write-Host "$($dep.Value) nicht gefunden" -ForegroundColor $colors.Error
$allInstalled = $false
}
}
return $allInstalled
}
function Setup-Hosts {
Show-Header "Host-Konfiguration"
if (-not $isAdmin) {
Write-Host "Diese Funktion erfordert Administrator-Rechte." -ForegroundColor $colors.Error
Write-Host "Bitte starten Sie das Skript als Administrator neu." -ForegroundColor $colors.Warning
return
}
$localIP = Get-LocalIPAddress
Write-Host "Lokale IP-Adresse: $localIP" -ForegroundColor $colors.Success
$hostsFile = "$env:windir\System32\drivers\etc\hosts"
Write-Host "Hosts-Datei: $hostsFile" -ForegroundColor $colors.Info
# Prüfen, ob die Einträge bereits existieren
$frontendEntry = Select-String -Path $hostsFile -Pattern "m040tbaraspi001.de040.corpintra.net" -Quiet
$backendEntry = Select-String -Path $hostsFile -Pattern "raspberrypi" -Quiet
# Einträge in die Hosts-Datei schreiben
Write-Host "Aktualisiere Hosts-Datei..." -ForegroundColor $colors.Info
$hostsContent = Get-Content -Path $hostsFile
if (-not $frontendEntry) {
$hostsContent += ""
$hostsContent += "# MYP Frontend Host"
$hostsContent += "$localIP m040tbaraspi001.de040.corpintra.net m040tbaraspi001"
Write-Host "Frontend-Hostname hinzugefügt" -ForegroundColor $colors.Success
} else {
Write-Host "Frontend-Hostname ist bereits konfiguriert" -ForegroundColor $colors.Warning
}
if (-not $backendEntry) {
$hostsContent += ""
$hostsContent += "# MYP Backend Host"
$hostsContent += "$localIP raspberrypi"
Write-Host "Backend-Hostname hinzugefügt" -ForegroundColor $colors.Success
} else {
Write-Host "Backend-Hostname ist bereits konfiguriert" -ForegroundColor $colors.Warning
}
# Speichern der aktualisierten Hosts-Datei
try {
$hostsContent | Set-Content -Path $hostsFile -Force
Write-Host "Konfiguration abgeschlossen!" -ForegroundColor $colors.Success
} catch {
Write-Host "Fehler beim Schreiben der Hosts-Datei: $_" -ForegroundColor $colors.Error
}
Write-Host ""
Write-Host "Folgende Hostnamen sind jetzt konfiguriert:" -ForegroundColor $colors.Info
Write-Host " - Frontend: m040tbaraspi001.de040.corpintra.net" -ForegroundColor $colors.Command
Write-Host " - Backend: raspberrypi" -ForegroundColor $colors.Command
Write-Host ""
Write-Host "Drücken Sie eine beliebige Taste, um fortzufahren..."
$null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
}
function Create-SSLCertificates {
Show-Header "SSL-Zertifikat-Generator"
# Parameter definieren
$certDir = "./backend/instance/ssl"
$backendCertFile = "$certDir/myp.crt"
$backendKeyFile = "$certDir/myp.key"
$frontendCertFile = "$certDir/frontend.crt"
$frontendKeyFile = "$certDir/frontend.key"
Write-Host "Zertifikate werden für folgende Hostnamen erstellt:" -ForegroundColor $colors.Info
# Hostname-Auswahl
Write-Host "1. Für lokale Entwicklung (localhost)" -ForegroundColor $colors.Command
Write-Host "2. Für Raspberry Pi Deployment (raspberrypi)" -ForegroundColor $colors.Command
Write-Host "3. Für Unternehmens-Setup (m040tbaraspi001.de040.corpintra.net)" -ForegroundColor $colors.Command
$choice = Read-Host "Wählen Sie eine Option (1-3, Standard: 1)"
switch ($choice) {
"2" {
$backendHostname = "raspberrypi"
$frontendHostname = "raspberrypi"
}
"3" {
$backendHostname = "raspberrypi"
$frontendHostname = "m040tbaraspi001.de040.corpintra.net"
}
default {
$backendHostname = "localhost"
$frontendHostname = "localhost"
}
}
Write-Host "Backend-Hostname: $backendHostname" -ForegroundColor $colors.Info
Write-Host "Frontend-Hostname: $frontendHostname" -ForegroundColor $colors.Info
Write-Host ""
# Verzeichnis erstellen, falls es nicht existiert
if (!(Test-Path $certDir)) {
Write-Host "Erstelle Verzeichnis $certDir..." -ForegroundColor $colors.Info
New-Item -ItemType Directory -Path $certDir -Force | Out-Null
}
# SSL-Zertifikate mit Python und cryptography erstellen
Write-Host "Erstelle SSL-Zertifikate mit Python..." -ForegroundColor $colors.Info
$pythonInstalled = Test-Command "python"
if ($pythonInstalled) {
# Überprüfen, ob cryptography installiert ist
$cryptographyInstalled = python -c "try: import cryptography; print('True'); except ImportError: print('False')" 2>$null
if ($cryptographyInstalled -ne "True") {
Write-Host "Installiere Python-Abhängigkeit 'cryptography'..." -ForegroundColor $colors.Warning
Exec-Command "pip install cryptography" "Installiere cryptography-Paket"
}
# Python-Skript zur Zertifikatserstellung
$certScript = @"
import os
import datetime
import sys
from cryptography import x509
from cryptography.x509.oid import NameOID
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.hazmat.primitives.serialization import Encoding, PrivateFormat, NoEncryption
def create_self_signed_cert(cert_path, key_path, hostname="localhost"):
# Verzeichnis erstellen, falls es nicht existiert
cert_dir = os.path.dirname(cert_path)
if cert_dir and not os.path.exists(cert_dir):
os.makedirs(cert_dir, exist_ok=True)
# Privaten Schlüssel generieren
private_key = rsa.generate_private_key(
public_exponent=65537,
key_size=4096,
)
# Schlüsseldatei schreiben
with open(key_path, "wb") as key_file:
key_file.write(private_key.private_bytes(
encoding=Encoding.PEM,
format=PrivateFormat.TraditionalOpenSSL,
encryption_algorithm=NoEncryption()
))
# Aktuelles Datum und Ablaufdatum berechnen
now = datetime.datetime.now()
valid_until = now + datetime.timedelta(days=3650) # 10 Jahre gültig
# Name für das Zertifikat erstellen
subject = issuer = x509.Name([
x509.NameAttribute(NameOID.COMMON_NAME, hostname),
x509.NameAttribute(NameOID.ORGANIZATION_NAME, "Mercedes-Benz AG"),
x509.NameAttribute(NameOID.ORGANIZATIONAL_UNIT_NAME, "Werk 040 Berlin"),
x509.NameAttribute(NameOID.COUNTRY_NAME, "DE"),
x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, "Berlin"),
x509.NameAttribute(NameOID.LOCALITY_NAME, "Berlin")
])
# Zertifikat erstellen
cert = x509.CertificateBuilder().subject_name(
subject
).issuer_name(
issuer
).public_key(
private_key.public_key()
).serial_number(
x509.random_serial_number()
).not_valid_before(
now
).not_valid_after(
valid_until
).add_extension(
x509.SubjectAlternativeName([
x509.DNSName(hostname),
x509.DNSName("localhost")
]),
critical=False,
).add_extension(
x509.BasicConstraints(ca=True, path_length=None), critical=True
).add_extension(
x509.KeyUsage(
digital_signature=True,
content_commitment=False,
key_encipherment=True,
data_encipherment=False,
key_agreement=False,
key_cert_sign=True,
crl_sign=True,
encipher_only=False,
decipher_only=False
), critical=True
).add_extension(
x509.ExtendedKeyUsage([
x509.oid.ExtendedKeyUsageOID.SERVER_AUTH,
x509.oid.ExtendedKeyUsageOID.CLIENT_AUTH
]), critical=False
).sign(private_key, hashes.SHA256())
# Zertifikatsdatei schreiben
with open(cert_path, "wb") as cert_file:
cert_file.write(cert.public_bytes(Encoding.PEM))
print(f"Selbstsigniertes SSL-Zertifikat für '{hostname}' erstellt:")
print(f"Zertifikat: {cert_path}")
print(f"Schlüssel: {key_path}")
print(f"Gültig für 10 Jahre.")
# Backend-Zertifikat erstellen
create_self_signed_cert('$backendCertFile', '$backendKeyFile', '$backendHostname')
# Frontend-Zertifikat erstellen
create_self_signed_cert('$frontendCertFile', '$frontendKeyFile', '$frontendHostname')
"@
$tempScriptPath = ".\temp_cert_script.py"
$certScript | Out-File -FilePath $tempScriptPath -Encoding utf8
# Python-Skript ausführen
try {
python $tempScriptPath
Write-Host "SSL-Zertifikate erfolgreich erstellt!" -ForegroundColor $colors.Success
} catch {
Write-Host "Fehler beim Erstellen der SSL-Zertifikate: $_" -ForegroundColor $colors.Error
} finally {
# Temporäres Skript löschen
Remove-Item -Path $tempScriptPath -Force
}
} else {
Write-Host "Python nicht gefunden. SSL-Zertifikate können nicht erstellt werden." -ForegroundColor $colors.Error
}
# Zertifikate im System installieren (optional)
if ($isAdmin) {
$installCerts = Read-Host "Möchten Sie die Zertifikate im System installieren? (j/n, Standard: n)"
if ($installCerts -eq "j") {
if (Test-Path $backendCertFile) {
Write-Host "Installiere Backend-Zertifikat im System..." -ForegroundColor $colors.Info
Exec-Command "certutil -addstore -f 'ROOT' '$backendCertFile'" "Installiere im Root-Zertifikatsspeicher"
}
if (Test-Path $frontendCertFile) {
Write-Host "Installiere Frontend-Zertifikat im System..." -ForegroundColor $colors.Info
Exec-Command "certutil -addstore -f 'ROOT' '$frontendCertFile'" "Installiere im Root-Zertifikatsspeicher"
}
}
} else {
Write-Host "Hinweis: Um die Zertifikate im System zu installieren, starten Sie das Skript als Administrator." -ForegroundColor $colors.Warning
}
Write-Host ""
Write-Host "SSL-Zertifikate wurden in folgenden Pfaden gespeichert:" -ForegroundColor $colors.Info
Write-Host "Backend: $backendCertFile" -ForegroundColor $colors.Command
Write-Host "Frontend: $frontendCertFile" -ForegroundColor $colors.Command
Write-Host ""
Write-Host "Drücken Sie eine beliebige Taste, um fortzufahren..."
$null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
}
function Setup-Environment {
Show-Header "Umgebungs-Setup"
# Prüfen, ob Python und pip installiert sind
$pythonInstalled = Test-Command "python"
$pipInstalled = Test-Command "pip"
if (-not $pythonInstalled -or -not $pipInstalled) {
Write-Host "Python oder pip ist nicht installiert. Bitte installieren Sie Python 3.6+ und versuchen Sie es erneut." -ForegroundColor $colors.Error
return
}
# Python-Abhängigkeiten installieren
Write-Host "Installiere Backend-Abhängigkeiten..." -ForegroundColor $colors.Info
Exec-Command "pip install -r backend/requirements.txt" "Installiere Python-Abhängigkeiten"
# Prüfen, ob Node.js und npm installiert sind
$nodeInstalled = Test-Command "node"
$npmInstalled = Test-Command "npm"
if ($nodeInstalled -and $npmInstalled) {
# Frontend-Abhängigkeiten installieren
Write-Host "Installiere Frontend-Abhängigkeiten..." -ForegroundColor $colors.Info
Exec-Command "cd frontend && npm install" "Installiere Node.js-Abhängigkeiten"
} else {
Write-Host "Node.js oder npm ist nicht installiert. Frontend-Abhängigkeiten werden übersprungen." -ForegroundColor $colors.Warning
}
Write-Host ""
Write-Host "Umgebungs-Setup abgeschlossen!" -ForegroundColor $colors.Success
Write-Host ""
Write-Host "Drücken Sie eine beliebige Taste, um fortzufahren..."
$null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
}
function Start-Application {
Show-Header "Anwendung starten"
Write-Host "Wie möchten Sie die Anwendung starten?" -ForegroundColor $colors.Info
Write-Host "1. Backend-Server starten (Python)" -ForegroundColor $colors.Command
Write-Host "2. Frontend-Server starten (Node.js)" -ForegroundColor $colors.Command
Write-Host "3. Beide Server starten (in separaten Fenstern)" -ForegroundColor $colors.Command
Write-Host "4. Mit Docker Compose starten" -ForegroundColor $colors.Command
Write-Host "5. Zurück zum Hauptmenü" -ForegroundColor $colors.Command
$choice = Read-Host "Wählen Sie eine Option (1-5)"
switch ($choice) {
"1" {
Write-Host "Starte Backend-Server..." -ForegroundColor $colors.Info
Start-Process -FilePath "python" -ArgumentList "backend/app/app.py" -NoNewWindow
Write-Host "Backend-Server läuft jetzt im Hintergrund." -ForegroundColor $colors.Success
}
"2" {
Write-Host "Starte Frontend-Server..." -ForegroundColor $colors.Info
Start-Process -FilePath "npm" -ArgumentList "run dev" -WorkingDirectory "frontend" -NoNewWindow
Write-Host "Frontend-Server läuft jetzt im Hintergrund." -ForegroundColor $colors.Success
}
"3" {
Write-Host "Starte Backend-Server..." -ForegroundColor $colors.Info
Start-Process -FilePath "python" -ArgumentList "backend/app/app.py" -NoNewWindow
Write-Host "Starte Frontend-Server..." -ForegroundColor $colors.Info
Start-Process -FilePath "npm" -ArgumentList "run dev" -WorkingDirectory "frontend" -NoNewWindow
Write-Host "Beide Server laufen jetzt im Hintergrund." -ForegroundColor $colors.Success
}
"4" {
$dockerInstalled = Test-Command "docker"
$dockerComposeInstalled = Test-Command "docker-compose"
if ($dockerInstalled -and $dockerComposeInstalled) {
Write-Host "Starte Anwendung mit Docker Compose..." -ForegroundColor $colors.Info
Exec-Command "docker-compose up -d" "Starte Docker Container"
Write-Host "Docker Container wurden gestartet." -ForegroundColor $colors.Success
} else {
Write-Host "Docker oder Docker Compose ist nicht installiert." -ForegroundColor $colors.Error
}
}
"5" {
return
}
default {
Write-Host "Ungültige Option." -ForegroundColor $colors.Error
}
}
Write-Host ""
Write-Host "Drücken Sie eine beliebige Taste, um fortzufahren..."
$null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
}
# Hauptmenü anzeigen
function Show-MainMenu {
Show-Header "Hauptmenü"
Write-Host "1. Systemvoraussetzungen prüfen" -ForegroundColor $colors.Command
Write-Host "2. Host-Konfiguration einrichten" -ForegroundColor $colors.Command
Write-Host "3. SSL-Zertifikate erstellen" -ForegroundColor $colors.Command
Write-Host "4. Umgebung einrichten (Abhängigkeiten installieren)" -ForegroundColor $colors.Command
Write-Host "5. Anwendung starten" -ForegroundColor $colors.Command
Write-Host "Q. Beenden" -ForegroundColor $colors.Command
Write-Host ""
Write-Host "Wählen Sie eine Option (1-5, Q): " -ForegroundColor $colors.Info -NoNewline
$choice = Read-Host
switch ($choice) {
"1" {
Test-Dependencies
Write-Host ""
Write-Host "Drücken Sie eine beliebige Taste, um fortzufahren..."
$null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
Show-MainMenu
}
"2" {
Setup-Hosts
Show-MainMenu
}
"3" {
Create-SSLCertificates
Show-MainMenu
}
"4" {
Setup-Environment
Show-MainMenu
}
"5" {
Start-Application
Show-MainMenu
}
"Q" {
exit
}
"q" {
exit
}
default {
Write-Host "Ungültige Option. Bitte versuchen Sie es erneut." -ForegroundColor $colors.Error
Start-Sleep -Seconds 2
Show-MainMenu
}
}
}
# Skript starten
Show-MainMenu

View File

@ -1,138 +1,95 @@
#!/bin/bash #!/bin/bash
# SSL-Konfiguration für MYP-Plattform (Linux/Raspberry Pi) # MYP Installer für Linux/Unix-Systeme
# Dieses Skript wurde in das MYP Installer Control Center integriert
# und dient als Kompatibilitätslayer für Linux/Unix-Systeme
# Farbdefinitionen # Farbdefinitionen
RED='\033[0;31m' RED='\033[0;31m'
GREEN='\033[0;32m' GREEN='\033[0;32m'
YELLOW='\033[0;33m' YELLOW='\033[0;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m' CYAN='\033[0;36m'
NC='\033[0m' # No Color NC='\033[0m' # No Color
# Titel anzeigen echo -e "${CYAN}=============================================================${NC}"
echo -e "${CYAN}====================================================" echo -e "${CYAN} MYP INSTALLER (UNIX/LINUX) ${NC}"
echo -e " SSL-Konfiguration für MYP-Plattform" echo -e "${CYAN}=============================================================${NC}"
echo -e "====================================================${NC}" echo -e "${YELLOW}Dieses Skript ist ein Kompatibilitätslayer für Linux/Unix.${NC}"
echo -e "${YELLOW}Es wird empfohlen, das PowerShell-Skript myp_installer.ps1${NC}"
echo -e "${YELLOW}für eine vollständige Funktionalität zu verwenden. ${NC}"
echo -e "${CYAN}=============================================================${NC}"
echo "" echo ""
# Prüfen, ob das Skript mit Root-Rechten ausgeführt wird # Überprüfen, ob das Skript als Root ausgeführt wird
if [ "$EUID" -ne 0 ]; then if [ "$EUID" -ne 0 ]; then
echo -e "${YELLOW}WARNUNG: Dieses Skript sollte mit Root-Rechten ausgeführt werden, um Zertifikate im System zu installieren.${NC}" echo -e "${YELLOW}Hinweis: Dieses Skript läuft ohne Root-Rechte.${NC}"
echo -e "${YELLOW}Einige Funktionen sind möglicherweise eingeschränkt.${NC}" echo -e "${YELLOW}Einige Funktionen sind möglicherweise eingeschränkt.${NC}"
echo "" echo ""
read -p "Möchten Sie trotzdem fortfahren? (j/n): " continue_anyway
if [ "$continue_anyway" != "j" ]; then
echo -e "${RED}Installation abgebrochen.${NC}"
exit 1
fi
fi fi
# Funktion zum Ausführen von Befehlen mit Ausgabe # Hauptmenu anzeigen
exec_command() { echo "Wählen Sie eine Option:"
command="$1" echo "1. SSL-Zertifikate erstellen"
description="$2" echo "2. Hosts-Konfiguration einrichten"
echo "3. Abhängigkeiten installieren"
echo -e "${YELLOW}> $description...${NC}" echo "4. Anwendung starten"
eval $command echo "5. Beenden"
if [ $? -eq 0 ]; then
echo -e "${GREEN}✓ Erfolgreich abgeschlossen!${NC}"
return 0
else
echo -e "${RED}✗ Fehler beim Ausführen des Befehls. Exit-Code: $?${NC}"
return 1
fi
}
# Prüfen, ob Python und pip installiert sind
if ! command -v python3 &> /dev/null; then
echo -e "${RED}✗ Python 3 ist nicht installiert. Bitte installieren Sie Python 3.6 oder höher.${NC}"
exit 1
fi
if ! command -v pip3 &> /dev/null; then
echo -e "${RED}✗ pip3 ist nicht installiert. Bitte installieren Sie pip3.${NC}"
exit 1
fi
# 1. Prüfen, ob die notwendigen Abhängigkeiten installiert sind
echo -e "${CYAN}1. Prüfe Abhängigkeiten...${NC}"
# Python-Abhängigkeiten prüfen
cryptography_installed=$(python3 -c "try: import cryptography; print('True'); except ImportError: print('False')" 2>/dev/null)
if [ "$cryptography_installed" != "True" ]; then
echo "Installiere Python-Abhängigkeit 'cryptography'..."
exec_command "pip3 install cryptography" "Installiere cryptography-Paket"
fi
# 2. SSL-Zertifikat generieren
echo "" echo ""
echo -e "${CYAN}2. Generiere SSL-Zertifikat...${NC}" read -p "Option (1-5): " choice
# SSL-Verzeichnisse erstellen case $choice in
mkdir -p backend/app/instance/ssl 1)
mkdir -p frontend/ssl echo -e "${BLUE}SSL-Zertifikate werden erstellt...${NC}"
# Python-Skript erstellen, falls nicht vorhanden # Verzeichnis erstellen
if [ ! -f backend/generate_ssl_cert.py ]; then mkdir -p backend/instance/ssl
echo "SSL-Zertifikatsgenerator nicht gefunden. Erstelle..."
cat > backend/generate_ssl_cert.py << 'EOF' # Python-Skript zur Zertifikatserstellung erstellen
cat > temp_cert_script.py << 'EOL'
#!/usr/bin/env python3 #!/usr/bin/env python3
# -*- coding: utf-8 -*-
import os import os
import datetime import datetime
import sys
try:
from cryptography import x509 from cryptography import x509
from cryptography.x509.oid import NameOID from cryptography.x509.oid import NameOID
from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import rsa from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.hazmat.primitives.serialization import Encoding, PrivateFormat, NoEncryption from cryptography.hazmat.primitives.serialization import Encoding, PrivateFormat, NoEncryption
except ImportError:
print("Fehler: Paket 'cryptography' nicht gefunden.")
print("Bitte installieren Sie es mit: pip install cryptography")
sys.exit(1)
def generate_ssl_certificate(): def create_self_signed_cert(cert_path, key_path, hostname="localhost"):
"""
Generiert ein verbessertes SSL-Zertifikat für die MYP-Anwendung
mit korrekten Metadaten und alternativen Namen.
"""
print("Generiere verbessertes SSL-Zertifikat für die MYP-Anwendung...")
# Verzeichnispfade definieren
ssl_dir = "app/instance/ssl"
ssl_cert_path = os.path.join(ssl_dir, "myp.crt")
ssl_key_path = os.path.join(ssl_dir, "myp.key")
# Verzeichnis erstellen, falls es nicht existiert # Verzeichnis erstellen, falls es nicht existiert
os.makedirs(ssl_dir, exist_ok=True) cert_dir = os.path.dirname(cert_path)
if cert_dir and not os.path.exists(cert_dir):
os.makedirs(cert_dir, exist_ok=True)
try: # Privaten Schlüssel generieren
# Privaten Schlüssel mit 4096 Bit generieren (sicherer)
private_key = rsa.generate_private_key( private_key = rsa.generate_private_key(
public_exponent=65537, public_exponent=65537,
key_size=4096, key_size=4096,
) )
# Aktuelles Datum und Ablaufdatum (1 Jahr gültig) # Schlüsseldatei schreiben
with open(key_path, "wb") as key_file:
key_file.write(private_key.private_bytes(
encoding=Encoding.PEM,
format=PrivateFormat.TraditionalOpenSSL,
encryption_algorithm=NoEncryption()
))
# Aktuelles Datum und Ablaufdatum berechnen
now = datetime.datetime.now() now = datetime.datetime.now()
valid_until = now + datetime.timedelta(days=365) valid_until = now + datetime.timedelta(days=3650) # 10 Jahre gültig
# Liste aller möglichen Hostnamen/IPs # Name für das Zertifikat erstellen
hostnames = [
"localhost",
"raspberrypi",
"m040tbaraspi001",
"m040tbaraspi001.de040.corpintra.net"
]
# IP-Adressen (als String, werden später konvertiert)
ip_addresses = [
"127.0.0.1",
"192.168.0.105"
]
# Erweiterte Zertifikatsattribute
subject = issuer = x509.Name([ subject = issuer = x509.Name([
x509.NameAttribute(NameOID.COMMON_NAME, "raspberrypi"), x509.NameAttribute(NameOID.COMMON_NAME, hostname),
x509.NameAttribute(NameOID.ORGANIZATION_NAME, "Mercedes-Benz AG"), x509.NameAttribute(NameOID.ORGANIZATION_NAME, "Mercedes-Benz AG"),
x509.NameAttribute(NameOID.ORGANIZATIONAL_UNIT_NAME, "Werk 040 Berlin"), x509.NameAttribute(NameOID.ORGANIZATIONAL_UNIT_NAME, "Werk 040 Berlin"),
x509.NameAttribute(NameOID.COUNTRY_NAME, "DE"), x509.NameAttribute(NameOID.COUNTRY_NAME, "DE"),
@ -140,16 +97,6 @@ def generate_ssl_certificate():
x509.NameAttribute(NameOID.LOCALITY_NAME, "Berlin") x509.NameAttribute(NameOID.LOCALITY_NAME, "Berlin")
]) ])
# Subject Alternative Names (SAN) erstellen
san_list = []
for hostname in hostnames:
san_list.append(x509.DNSName(hostname))
# IP-Adressen hinzufügen
import socket
for ip in ip_addresses:
san_list.append(x509.IPAddress(socket.inet_aton(ip)))
# Zertifikat erstellen # Zertifikat erstellen
cert = x509.CertificateBuilder().subject_name( cert = x509.CertificateBuilder().subject_name(
subject subject
@ -164,7 +111,10 @@ def generate_ssl_certificate():
).not_valid_after( ).not_valid_after(
valid_until valid_until
).add_extension( ).add_extension(
x509.SubjectAlternativeName(san_list), x509.SubjectAlternativeName([
x509.DNSName(hostname),
x509.DNSName("localhost")
]),
critical=False, critical=False,
).add_extension( ).add_extension(
x509.BasicConstraints(ca=True, path_length=None), critical=True x509.BasicConstraints(ca=True, path_length=None), critical=True
@ -187,351 +137,144 @@ def generate_ssl_certificate():
]), critical=False ]), critical=False
).sign(private_key, hashes.SHA256()) ).sign(private_key, hashes.SHA256())
# Zertifikat und Schlüssel speichern # Zertifikatsdatei schreiben
with open(ssl_key_path, "wb") as f: with open(cert_path, "wb") as cert_file:
f.write(private_key.private_bytes( cert_file.write(cert.public_bytes(Encoding.PEM))
encoding=Encoding.PEM,
format=PrivateFormat.TraditionalOpenSSL,
encryption_algorithm=NoEncryption()
))
with open(ssl_cert_path, "wb") as f: print(f"Selbstsigniertes SSL-Zertifikat für '{hostname}' erstellt:")
f.write(cert.public_bytes(Encoding.PEM)) print(f"Zertifikat: {cert_path}")
print(f"Schlüssel: {key_path}")
print(f"Gültig für 10 Jahre.")
# Kopieren des Zertifikats in das Frontend-Verzeichnis # Hostname wählen
frontend_ssl_dir = "../frontend/ssl" print("Wählen Sie den Hostnamen für das Zertifikat:")
os.makedirs(frontend_ssl_dir, exist_ok=True) print("1. localhost (für lokale Entwicklung)")
print("2. raspberrypi (für Raspberry Pi)")
print("3. m040tbaraspi001.de040.corpintra.net (für Unternehmens-Setup)")
choice = input("Option (1-3, Standard: 1): ")
import shutil hostname = "localhost"
shutil.copy2(ssl_cert_path, os.path.join(frontend_ssl_dir, "myp.crt")) if choice == "2":
shutil.copy2(ssl_key_path, os.path.join(frontend_ssl_dir, "myp.key")) hostname = "raspberrypi"
elif choice == "3":
hostname = "m040tbaraspi001.de040.corpintra.net"
print(f"SSL-Zertifikat wurde erstellt:") # Zertifikate erstellen
print(f"- Zertifikat: {ssl_cert_path}") create_self_signed_cert("backend/instance/ssl/myp.crt", "backend/instance/ssl/myp.key", hostname)
print(f"- Schlüssel: {ssl_key_path}") create_self_signed_cert("backend/instance/ssl/frontend.crt", "backend/instance/ssl/frontend.key", hostname)
print(f"- Kopiert nach: {frontend_ssl_dir}") EOL
print(f"- Gültig bis: {valid_until.strftime('%d.%m.%Y')}")
print(f"- Hostnamen: {', '.join(hostnames)}")
print(f"- IP-Adressen: {', '.join(ip_addresses)}")
return True # Python-Skript ausführbar machen und ausführen
except Exception as e: chmod +x temp_cert_script.py
print(f"Fehler beim Erstellen des SSL-Zertifikats: {e}") python3 temp_cert_script.py || python temp_cert_script.py
return False
if __name__ == "__main__": # Temporäres Skript löschen
generate_ssl_certificate() rm temp_cert_script.py
EOF
# Ausführbar machen echo -e "${GREEN}SSL-Zertifikate erstellt.${NC}"
chmod +x backend/generate_ssl_cert.py ;;
2)
echo -e "${BLUE}Hosts-Konfiguration wird eingerichtet...${NC}"
# Lokale IP-Adresse ermitteln
LOCAL_IP=$(hostname -I | awk '{print $1}')
if [ -z "$LOCAL_IP" ]; then
LOCAL_IP="127.0.0.1"
fi fi
# Zertifikat generieren echo "Lokale IP-Adresse: $LOCAL_IP"
cert_gen_success=$(exec_command "cd backend && python3 generate_ssl_cert.py" "Generiere SSL-Zertifikat")
if [ $? -ne 0 ]; then
echo -e "${RED}✗ Fehler bei der Zertifikatsgenerierung. Abbruch.${NC}"
exit 1
fi
# 3. Zertifikat im System installieren
echo ""
echo -e "${CYAN}3. Installiere Zertifikat im System...${NC}"
# Hosts-Datei bearbeiten
if [ "$EUID" -eq 0 ]; then if [ "$EUID" -eq 0 ]; then
# Als Root ausgeführt # Check if entries already exist
cert_path=$(readlink -f backend/app/instance/ssl/myp.crt) if ! grep -q "m040tbaraspi001.de040.corpintra.net" /etc/hosts; then
echo "" >> /etc/hosts
# Zielverzeichnis für System-Zertifikate echo "# MYP Frontend Host" >> /etc/hosts
if [ -d "/usr/local/share/ca-certificates" ]; then echo "$LOCAL_IP m040tbaraspi001.de040.corpintra.net m040tbaraspi001" >> /etc/hosts
# Debian/Ubuntu/Raspberry Pi OS echo -e "${GREEN}Frontend-Hostname hinzugefügt${NC}"
cert_dir="/usr/local/share/ca-certificates"
exec_command "cp $cert_path $cert_dir/myp.crt" "Kopiere Zertifikat in System-Verzeichnis"
exec_command "update-ca-certificates" "Aktualisiere System-Zertifikate"
elif [ -d "/etc/pki/ca-trust/source/anchors" ]; then
# RHEL/CentOS/Fedora
cert_dir="/etc/pki/ca-trust/source/anchors"
exec_command "cp $cert_path $cert_dir/myp.crt" "Kopiere Zertifikat in System-Verzeichnis"
exec_command "update-ca-trust extract" "Aktualisiere System-Zertifikate"
else else
echo -e "${YELLOW}Unbekanntes System. Versuche direkte Installation...${NC}" echo -e "${YELLOW}Frontend-Hostname ist bereits konfiguriert${NC}"
if command -v certutil &> /dev/null; then
exec_command "certutil -A -n 'MYP SSL Certificate' -t 'C,,' -i $cert_path -d sql:$HOME/.pki/nssdb" "Installiere mit certutil"
fi fi
if ! grep -q "raspberrypi" /etc/hosts; then
echo "" >> /etc/hosts
echo "# MYP Backend Host" >> /etc/hosts
echo "$LOCAL_IP raspberrypi" >> /etc/hosts
echo -e "${GREEN}Backend-Hostname hinzugefügt${NC}"
else
echo -e "${YELLOW}Backend-Hostname ist bereits konfiguriert${NC}"
fi fi
else else
echo -e "${YELLOW}Überspringen der System-Installation, da das Skript nicht als Root ausgeführt wird.${NC}" echo -e "${RED}Root-Rechte erforderlich, um die Hosts-Datei zu bearbeiten.${NC}"
echo -e "${YELLOW}Sie können das Zertifikat später manuell installieren durch:${NC}" echo -e "${YELLOW}Bitte führen Sie die folgenden Befehle manuell als Root aus:${NC}"
echo -e "${NC}sudo cp backend/app/instance/ssl/myp.crt /usr/local/share/ca-certificates/ && sudo update-ca-certificates${NC}" echo "echo \"\" >> /etc/hosts"
echo "echo \"# MYP Frontend Host\" >> /etc/hosts"
echo "echo \"$LOCAL_IP m040tbaraspi001.de040.corpintra.net m040tbaraspi001\" >> /etc/hosts"
echo "echo \"\" >> /etc/hosts"
echo "echo \"# MYP Backend Host\" >> /etc/hosts"
echo "echo \"$LOCAL_IP raspberrypi\" >> /etc/hosts"
fi fi
;;
# 4. Frontend konfigurieren 3)
echo "" echo -e "${BLUE}Abhängigkeiten werden installiert...${NC}"
echo -e "${CYAN}4. Konfiguriere Frontend...${NC}"
# Erstelle Frontend-Konfigurationsskript # Python-Abhängigkeiten
cat > frontend/configure_ssl.js << 'EOF' echo "Installiere Python-Abhängigkeiten..."
#!/usr/bin/env node pip3 install -r backend/requirements.txt || pip install -r backend/requirements.txt
/** # Frontend-Abhängigkeiten
* Dieses Skript konfiguriert das Next.js-Frontend, um das selbstsignierte SSL-Zertifikat zu akzeptieren if command -v npm &> /dev/null; then
* und die richtigen SSL-Einstellungen im Frontend zu setzen. echo "Installiere Frontend-Abhängigkeiten..."
*/ (cd frontend && npm install)
const fs = require('fs');
const path = require('path');
// Pfade definieren
const ENV_LOCAL_PATH = path.join(__dirname, '.env.local');
const ENV_FRONTEND_PATH = path.join(__dirname, 'env.frontend');
const SSL_DIR = path.join(__dirname, 'ssl');
const NEXT_CONFIG_PATH = path.join(__dirname, 'next.config.js');
console.log('=== Frontend-SSL-Konfiguration ===');
// Prüfen, ob SSL-Verzeichnis und Zertifikate existieren
if (!fs.existsSync(SSL_DIR) ||
!fs.existsSync(path.join(SSL_DIR, 'myp.crt')) ||
!fs.existsSync(path.join(SSL_DIR, 'myp.key'))) {
console.error('SSL-Zertifikate nicht gefunden. Bitte zuerst das Backend-Skript ausführen.');
process.exit(1);
}
console.log('SSL-Zertifikate gefunden. Konfiguriere Frontend...');
// Umgebungsvariablen konfigurieren
function updateEnvFile() {
try {
let envContent;
// .env.local erstellen oder aktualisieren
if (fs.existsSync(ENV_LOCAL_PATH)) {
envContent = fs.readFileSync(ENV_LOCAL_PATH, 'utf8');
} else if (fs.existsSync(ENV_FRONTEND_PATH)) {
envContent = fs.readFileSync(ENV_FRONTEND_PATH, 'utf8');
} else {
envContent = `# MYP Frontend Umgebungsvariablen\n`;
}
// SSL-Konfigurationen
const sslConfigs = [
'NODE_TLS_REJECT_UNAUTHORIZED=0',
'HTTPS=true',
'SSL_CRT_FILE=./ssl/myp.crt',
'SSL_KEY_FILE=./ssl/myp.key',
'NEXT_PUBLIC_API_URL=https://raspberrypi:443',
'NEXT_PUBLIC_BACKEND_HOST=raspberrypi:443',
'NEXT_PUBLIC_BACKEND_PROTOCOL=https'
];
// Existierende Konfigurationen aktualisieren
sslConfigs.forEach(config => {
const [key, value] = config.split('=');
const regex = new RegExp(`^${key}=.*$`, 'm');
if (envContent.match(regex)) {
// Update existierende Konfiguration
envContent = envContent.replace(regex, config);
} else {
// Neue Konfiguration hinzufügen
envContent += `\n${config}`;
}
});
// Speichern der aktualisierten Umgebungsvariablen
fs.writeFileSync(ENV_LOCAL_PATH, envContent);
console.log('.env.local Datei aktualisiert mit SSL-Konfigurationen');
return true;
} catch (error) {
console.error(`Fehler bei der Aktualisierung der Umgebungsvariablen: ${error.message}`);
return false;
}
}
// Next.js-Konfiguration aktualisieren
function updateNextConfig() {
try {
let configContent;
// next.config.js erstellen oder aktualisieren
if (fs.existsSync(NEXT_CONFIG_PATH)) {
configContent = fs.readFileSync(NEXT_CONFIG_PATH, 'utf8');
} else {
configContent = `/** @type {import('next').NextConfig} */\n\nconst nextConfig = {}\n\nmodule.exports = nextConfig\n`;
}
// Prüfen, ob bereits eine HTTPS-Konfiguration vorhanden ist
if (configContent.includes('serverOptions:') && configContent.includes('https:')) {
console.log('HTTPS-Konfiguration ist bereits in der next.config.js vorhanden.');
return true;
}
// HTTPS-Konfiguration hinzufügen
const httpsConfig = `
/** @type {import('next').NextConfig} */
const fs = require('fs');
const path = require('path');
const nextConfig = {
reactStrictMode: true,
webpack: (config) => {
return config;
},
// HTTPS-Konfiguration für die Entwicklung
devServer: {
https: {
key: fs.readFileSync(path.resolve(__dirname, 'ssl/myp.key')),
cert: fs.readFileSync(path.resolve(__dirname, 'ssl/myp.crt')),
},
},
// Konfiguration für selbstsignierte Zertifikate
serverOptions: {
https: {
key: fs.readFileSync(path.resolve(__dirname, 'ssl/myp.key')),
cert: fs.readFileSync(path.resolve(__dirname, 'ssl/myp.crt')),
},
},
// Zusätzliche Konfigurationen
async rewrites() {
return [
{
source: '/api/:path*',
destination: 'https://raspberrypi:443/api/:path*',
},
]
}
};
module.exports = nextConfig;
`;
// Speichern der aktualisierten Next.js-Konfiguration
fs.writeFileSync(NEXT_CONFIG_PATH, httpsConfig);
console.log('next.config.js Datei aktualisiert mit HTTPS-Konfiguration');
return true;
} catch (error) {
console.error(`Fehler bei der Aktualisierung der Next.js-Konfiguration: ${error.message}`);
return false;
}
}
// Update der Fetch-Konfiguration
function updateFetchConfig() {
try {
const fetchConfigPath = path.join(__dirname, 'src', 'utils', 'api-config.ts');
if (!fs.existsSync(fetchConfigPath)) {
console.warn('Datei api-config.ts nicht gefunden. Überspringe Aktualisierung.');
return true;
}
// Lesen der aktuellen Konfiguration
let configContent = fs.readFileSync(fetchConfigPath, 'utf8');
// Sicherstellen, dass SSL-Verbindungen akzeptiert werden
if (!configContent.includes('NODE_TLS_REJECT_UNAUTHORIZED=0')) {
// Hinzufügen eines Kommentars zu Beginn der Datei
configContent = `// SSL-Verbindungen akzeptieren (selbstsignierte Zertifikate)
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
${configContent}`;
}
// Speichern der aktualisierten Fetch-Konfiguration
fs.writeFileSync(fetchConfigPath, configContent);
console.log('api-config.ts Datei aktualisiert, um selbstsignierte Zertifikate zu akzeptieren');
return true;
} catch (error) {
console.error(`Fehler bei der Aktualisierung der Fetch-Konfiguration: ${error.message}`);
return false;
}
}
// Hauptfunktion
function main() {
let success = true;
success = updateEnvFile() && success;
success = updateNextConfig() && success;
success = updateFetchConfig() && success;
if (success) {
console.log('\n=== Konfiguration erfolgreich abgeschlossen ===');
console.log('Das Frontend wurde für die Verwendung von HTTPS mit dem selbstsignierten Zertifikat konfiguriert.');
} else {
console.error('\n=== Konfiguration nicht vollständig abgeschlossen ===');
console.error('Es gab Probleme bei der Konfiguration des Frontends.');
}
}
// Ausführen der Hauptfunktion
main();
EOF
# Ausführbar machen
chmod +x frontend/configure_ssl.js
# Frontend konfigurieren
if command -v node &> /dev/null; then
frontend_config_success=$(exec_command "cd frontend && node configure_ssl.js" "Konfiguriere Frontend")
else else
echo -e "${YELLOW}Node.js ist nicht installiert. Überspringe Frontend-Konfiguration.${NC}" echo -e "${YELLOW}npm nicht gefunden. Frontend-Abhängigkeiten werden übersprungen.${NC}"
echo -e "${YELLOW}Sie können die Frontend-Konfiguration später manuell durchführen durch:${NC}"
echo -e "${NC}cd frontend && node configure_ssl.js${NC}"
fi fi
# 5. Docker-Compose Datei aktualisieren echo -e "${GREEN}Abhängigkeiten installiert.${NC}"
echo "" ;;
echo -e "${CYAN}5. Aktualisiere Docker-Compose-Konfiguration...${NC}"
4)
docker_compose_file="docker-compose.yml" echo -e "${BLUE}Anwendung wird gestartet...${NC}"
if [ -f "$docker_compose_file" ]; then echo "Wie möchten Sie die Anwendung starten?"
if ! grep -q -- "--dual-protocol" "$docker_compose_file"; then echo "1. Backend-Server starten (Python)"
# Backup erstellen echo "2. Frontend-Server starten (npm)"
cp "$docker_compose_file" "${docker_compose_file}.bak" echo "3. Mit Docker Compose starten"
read -p "Option (1-3): " start_choice
# Konfiguration aktualisieren
sed -i 's/command: python -m app\.app/command: python -m app.app --dual-protocol/g' "$docker_compose_file" case $start_choice in
1)
echo -e "${GREEN}✓ Docker-Compose-Datei wurde aktualisiert, um den dual-protocol-Modus zu aktivieren.${NC}" echo "Starte Backend-Server..."
else python3 backend/app/app.py || python backend/app/app.py &
echo -e "${GREEN}✓ Docker-Compose-Datei ist bereits korrekt konfiguriert.${NC}" echo -e "${GREEN}Backend-Server läuft im Hintergrund.${NC}"
fi ;;
else 2)
echo -e "${YELLOW}✗ Docker-Compose-Datei nicht gefunden. Überspringe diese Konfiguration.${NC}" echo "Starte Frontend-Server..."
fi (cd frontend && npm run dev) &
echo -e "${GREEN}Frontend-Server läuft im Hintergrund.${NC}"
# 6. Docker-Container aktualisieren ;;
echo "" 3)
echo -e "${CYAN}6. Möchten Sie die Docker-Container neu starten?${NC}" echo "Starte Anwendung mit Docker Compose..."
read -p "Neu starten (j/n): " restart_docker docker-compose up -d
echo -e "${GREEN}Docker Container wurden gestartet.${NC}"
if [ "$restart_docker" = "j" ]; then ;;
if command -v docker-compose &> /dev/null || command -v docker &> /dev/null; then *)
echo "Starte Docker-Container neu..." echo -e "${RED}Ungültige Option.${NC}"
;;
if command -v docker-compose &> /dev/null; then esac
exec_command "docker-compose down && docker-compose up -d" "Starte Docker-Container neu mit docker-compose" ;;
else
exec_command "docker compose down && docker compose up -d" "Starte Docker-Container neu mit docker compose" 5)
fi echo -e "${GREEN}Installation wird beendet.${NC}"
else exit 0
echo -e "${YELLOW}Docker ist nicht installiert oder nicht im PATH. Überspringe Neustart der Container.${NC}" ;;
fi
fi *)
echo -e "${RED}Ungültige Option.${NC}"
# Abschluss ;;
echo "" esac
echo -e "${CYAN}===================================================="
echo -e " SSL-Konfiguration abgeschlossen"
echo -e "====================================================${NC}"
echo ""
echo -e "${GREEN}Das SSL-Zertifikat wurde erfolgreich generiert und konfiguriert.${NC}"
echo -e "${GREEN}Sie können nun auf folgende Weise auf die Anwendung zugreifen:${NC}"
echo -e "${GREEN}- Backend: https://raspberrypi:443${NC}"
echo -e "${GREEN}- Frontend: https://localhost:3000${NC}"
echo ""
echo -e "${YELLOW}Hinweis: Bei der ersten Verbindung müssen Sie möglicherweise${NC}"
echo -e "${YELLOW}das selbstsignierte Zertifikat in Ihrem Browser akzeptieren.${NC}"
echo "" echo ""
echo -e "${CYAN}Installation abgeschlossen. Drücken Sie ENTER, um fortzufahren...${NC}"
read