"feat: Implement printer management

This commit is contained in:
2025-05-26 12:24:43 +02:00
parent 4282b52a3b
commit 57e306db08
11 changed files with 824 additions and 703 deletions

View File

@@ -1923,154 +1923,4 @@ def validate_ssl_certificate():
except Exception as e:
app_logger.error(f"Fehler bei der SSL-Validierung: {e}")
return jsonify({"error": f"Fehler bei der Validierung: {str(e)}"}), 500
@login_required
def get_ssl_info():
"""Gibt Informationen über das aktuelle SSL-Zertifikat zurück."""
if not current_user.is_admin:
return jsonify({"error": "Nur Administratoren können SSL-Informationen abrufen"}), 403
try:
from utils.ssl_manager import ssl_manager
cert_info = ssl_manager.get_certificate_info()
if not cert_info:
return jsonify({
"exists": False,
"message": "Kein SSL-Zertifikat gefunden"
})
return jsonify({
"exists": True,
"certificate": cert_info,
"paths": {
"cert": ssl_manager.cert_path,
"key": ssl_manager.key_path
}
})
except Exception as e:
ssl_logger.error(f"Fehler beim Abrufen der SSL-Informationen: {e}")
return jsonify({"error": f"Fehler beim Abrufen der SSL-Informationen: {str(e)}"}), 500
@app.route("/api/ssl/generate", methods=["POST"])
@login_required
def generate_ssl_certificate():
"""Generiert ein neues SSL-Zertifikat."""
if not current_user.is_admin:
return jsonify({"error": "Nur Administratoren können SSL-Zertifikate generieren"}), 403
try:
from utils.ssl_manager import ssl_manager
# Parameter aus Request extrahieren
data = request.json or {}
key_size = data.get("key_size", 4096)
validity_days = data.get("validity_days", 365)
# Zertifikat generieren
success = ssl_manager.generate_mercedes_certificate(key_size, validity_days)
if success:
cert_info = ssl_manager.get_certificate_info()
ssl_logger.info(f"SSL-Zertifikat von {current_user.username} generiert")
return jsonify({
"success": True,
"message": "SSL-Zertifikat erfolgreich generiert",
"certificate": cert_info
})
else:
return jsonify({
"success": False,
"error": "Fehler beim Generieren des SSL-Zertifikats"
}), 500
except Exception as e:
ssl_logger.error(f"Fehler beim Generieren des SSL-Zertifikats: {e}")
return jsonify({"error": f"Fehler beim Generieren: {str(e)}"}), 500
@app.route("/api/ssl/install", methods=["POST"])
@login_required
def install_ssl_certificate():
"""Installiert das SSL-Zertifikat im System."""
if not current_user.is_admin:
return jsonify({"error": "Nur Administratoren können SSL-Zertifikate installieren"}), 403
try:
from utils.ssl_manager import ssl_manager
success = ssl_manager.install_system_certificate()
if success:
ssl_logger.info(f"SSL-Zertifikat von {current_user.username} im System installiert")
return jsonify({
"success": True,
"message": "SSL-Zertifikat erfolgreich im System installiert"
})
else:
return jsonify({
"success": False,
"error": "Fehler bei der Installation des SSL-Zertifikats im System"
}), 500
except Exception as e:
ssl_logger.error(f"Fehler bei der SSL-Installation: {e}")
return jsonify({"error": f"Fehler bei der Installation: {str(e)}"}), 500
@app.route("/api/ssl/copy-raspberry", methods=["POST"])
@login_required
def copy_ssl_to_raspberry():
"""Kopiert das SSL-Zertifikat auf den Raspberry Pi."""
if not current_user.is_admin:
return jsonify({"error": "Nur Administratoren können SSL-Zertifikate kopieren"}), 403
try:
from utils.ssl_manager import ssl_manager
# Parameter aus Request extrahieren
data = request.json or {}
host = data.get("host", "raspberrypi")
user = data.get("user", "pi")
dest = data.get("dest", "/home/pi/myp/ssl")
success = ssl_manager.copy_to_raspberry(host, user, dest)
if success:
ssl_logger.info(f"SSL-Zertifikat von {current_user.username} auf Raspberry Pi kopiert")
return jsonify({
"success": True,
"message": f"SSL-Zertifikat erfolgreich auf {host} kopiert"
})
else:
return jsonify({
"success": False,
"error": "Fehler beim Kopieren des SSL-Zertifikats auf den Raspberry Pi"
}), 500
except Exception as e:
ssl_logger.error(f"Fehler beim Kopieren auf Raspberry Pi: {e}")
return jsonify({"error": f"Fehler beim Kopieren: {str(e)}"}), 500
@app.route("/api/ssl/validate", methods=["GET"])
@login_required
def validate_ssl_certificate():
"""Validiert das aktuelle SSL-Zertifikat."""
if not current_user.is_admin:
return jsonify({"error": "Nur Administratoren können SSL-Zertifikate validieren"}), 403
try:
from utils.ssl_manager import ssl_manager
is_valid = ssl_manager.is_certificate_valid()
cert_info = ssl_manager.get_certificate_info()
return jsonify({
"valid": is_valid,
"certificate": cert_info,
"message": "Zertifikat ist gültig" if is_valid else "Zertifikat ist ungültig oder läuft bald ab"
})
except Exception as e:
ssl_logger.error(f"Fehler bei der SSL-Validierung: {e}")
return jsonify({"error": f"Fehler bei der Validierung: {str(e)}"}), 500

View File

@@ -0,0 +1,110 @@
#!/usr/bin/env python3
"""
Skript zur Bereinigung der Drucker-Datenbank und Hinzufügung der korrekten hardkodierten Drucker.
"""
import sys
import os
sys.path.append('.')
from config.settings import PRINTERS
from database.db_manager import DatabaseManager
from models import Printer
from datetime import datetime
def clean_and_add_printers():
"""Bereinigt die Drucker-Datenbank und fügt die korrekten hardkodierten Drucker hinzu."""
print("=== Drucker-Datenbank bereinigen und neu erstellen ===")
print(f"Hardkodierte Drucker: {len(PRINTERS)}")
try:
db = DatabaseManager()
session = db.get_session()
# Alle existierenden Drucker löschen
existing_printers = session.query(Printer).all()
print(f"Lösche {len(existing_printers)} existierende Drucker...")
for printer in existing_printers:
session.delete(printer)
session.commit()
print("✅ Alle alten Drucker gelöscht")
# Neue Drucker hinzufügen
added_count = 0
for printer_name, config in PRINTERS.items():
# Neuen Drucker erstellen
new_printer = Printer(
name=printer_name,
model="P115", # Standard-Modell
location="Labor", # Standard-Standort
ip_address=config["ip"],
mac_address=f"98:25:4A:E1:{printer_name[-1]}0:0{printer_name[-1]}", # Dummy MAC
plug_ip=config["ip"],
plug_username="admin",
plug_password="admin",
status="available", # Verfügbar, da in Konfiguration
active=True,
created_at=datetime.now()
)
session.add(new_printer)
print(f"{printer_name}: Hinzugefügt (IP: {config['ip']})")
added_count += 1
# Änderungen speichern
session.commit()
session.close()
print(f"\n{added_count} neue Drucker hinzugefügt")
print("Drucker-Datenbank erfolgreich bereinigt und neu erstellt!")
except Exception as e:
print(f"❌ Fehler beim Bereinigen: {e}")
if 'session' in locals():
session.rollback()
session.close()
def list_final_printers():
"""Zeigt die finalen Drucker in der Datenbank an."""
print("\n=== Finale Drucker-Liste ===")
try:
db = DatabaseManager()
session = db.get_session()
printers = session.query(Printer).all()
if not printers:
print("Keine Drucker in der Datenbank gefunden.")
return
print(f"{'ID':<5} {'Name':<15} {'Status':<12} {'IP-Adresse':<15} {'Aktiv':<8}")
print("-" * 60)
for printer in printers:
active_str = "" if printer.active else ""
print(f"{printer.id:<5} {printer.name:<15} {printer.status:<12} {printer.ip_address:<15} {active_str:<8}")
session.close()
print(f"\nGesamt: {len(printers)} Drucker")
except Exception as e:
print(f"❌ Fehler beim Abrufen: {e}")
if 'session' in locals():
session.close()
if __name__ == "__main__":
print("Drucker-Datenbank Bereinigung und Neuerstellung")
print("=" * 50)
# Datenbank bereinigen und neue Drucker hinzufügen
clean_and_add_printers()
# Finale Liste anzeigen
list_final_printers()

View File

@@ -128,95 +128,22 @@ def get_ssl_context():
def create_simple_ssl_cert():
"""
Erstellt ein einfaches selbstsigniertes Zertifikat mit Python.
Dies ist ein Fallback, falls OpenSSL nicht verfügbar ist.
Erstellt ein Mercedes-Benz SSL-Zertifikat mit dem neuen SSL-Manager.
"""
try:
import datetime
import socket
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
# Generiere privaten Schlüssel
private_key = rsa.generate_private_key(
public_exponent=65537,
key_size=4096, # Stärkere Schlüsselgröße
)
# Schreibe privaten Schlüssel
with open(SSL_KEY_PATH, "wb") as f:
f.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
# Erstelle Zertifikat mit erweiterten Attributen
subject = issuer = x509.Name([
x509.NameAttribute(NameOID.COMMON_NAME, SSL_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")
])
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(SSL_HOSTNAME),
x509.DNSName("localhost"),
x509.IPAddress(socket.inet_aton("127.0.0.1"))
]),
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())
# Schreibe Zertifikat
with open(SSL_CERT_PATH, "wb") as f:
f.write(cert.public_bytes(Encoding.PEM))
# Verwende den neuen SSL-Manager
from utils.ssl_manager import ssl_manager
success = ssl_manager.generate_mercedes_certificate()
print(f"Verbessertes selbstsigniertes Zertifikat erstellt: {SSL_CERT_PATH}")
print(f"Gültig bis: {valid_until.strftime('%d.%m.%Y')}")
except ImportError:
print("Konnte keine SSL-Zertifikate erstellen: cryptography-Paket nicht installiert")
if success:
print(f"Mercedes-Benz SSL-Zertifikat erfolgreich erstellt: {SSL_CERT_PATH}")
return True
else:
print("Fehler beim Erstellen des Mercedes-Benz SSL-Zertifikats")
return None
except ImportError as e:
print(f"SSL-Manager nicht verfügbar: {e}")
return None
except Exception as e:
print(f"Fehler beim Erstellen der SSL-Zertifikate: {e}")

View File

@@ -86,8 +86,8 @@ if __name__ == "__main__":
import argparse
parser = argparse.ArgumentParser(description="Erstellt selbstsignierte SSL-Zertifikate für die lokale Entwicklung")
parser.add_argument("-c", "--cert", default="instance/ssl/myp.crt", help="Pfad zur Zertifikatsdatei")
parser.add_argument("-k", "--key", default="instance/ssl/myp.key", help="Pfad zur Schlüsseldatei")
parser.add_argument("-c", "--cert", default="../certs/myp.crt", help="Pfad zur Zertifikatsdatei")
parser.add_argument("-k", "--key", default="../certs/myp.key", help="Pfad zur Schlüsseldatei")
parser.add_argument("-n", "--hostname", default="localhost", help="Hostname für das Zertifikat")
args = parser.parse_args()

Binary file not shown.

View File

@@ -416,6 +416,12 @@
</svg>
Logs
</a>
<a href="{{ url_for('admin_page', tab='ssl') }}" class="tab-modern {{ 'active' if active_tab == 'ssl' else '' }}">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z" />
</svg>
SSL
</a>
</div>
<!-- Tab Content -->
@@ -658,11 +664,270 @@
</div>
</div>
</div>
{% endif %}
<!-- SSL Tab -->
{% if active_tab == 'ssl' %}
<div class="content-card-modern">
<div class="flex flex-col md:flex-row md:justify-between md:items-center mb-8 gap-4">
<h3 class="text-3xl font-bold text-slate-900 dark:text-white">SSL-Zertifikatsverwaltung</h3>
<button onclick="loadSSLInfo()" class="btn-modern">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"/>
</svg>
Aktualisieren
</button>
</div>
<div class="grid grid-cols-1 lg:grid-cols-2 gap-8">
<!-- Zertifikatsinformationen -->
<div class="form-modern">
<h4 class="text-xl font-semibold text-slate-900 dark:text-white mb-6">Aktuelles Zertifikat</h4>
<div id="ssl-info-container">
<div class="text-center py-8">
<div class="animate-spin rounded-full h-8 w-8 border-b-2 border-blue-600 mx-auto"></div>
<p class="mt-2 text-slate-600 dark:text-slate-400">Lade Zertifikatsinformationen...</p>
</div>
</div>
</div>
<!-- SSL-Aktionen -->
<div class="form-modern">
<h4 class="text-xl font-semibold text-slate-900 dark:text-white mb-6">Zertifikatsverwaltung</h4>
<div class="space-y-4">
<button onclick="generateSSLCertificate()" class="btn-modern w-full justify-center">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6v6m0 0v6m0-6h6m-6 0H6" />
</svg>
Neues Zertifikat generieren
</button>
<button onclick="installSSLCertificate()" class="btn-success-modern w-full justify-center">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4" />
</svg>
Im System installieren
</button>
<button onclick="copyToRaspberry()" class="btn-modern w-full justify-center">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z" />
</svg>
Auf Raspberry Pi kopieren
</button>
<button onclick="validateSSLCertificate()" class="btn-modern w-full justify-center">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
Zertifikat validieren
</button>
</div>
</div>
</div>
<!-- Erweiterte Optionen -->
<div class="form-modern mt-8">
<h4 class="text-xl font-semibold text-slate-900 dark:text-white mb-6">Erweiterte Optionen</h4>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div>
<label for="ssl-key-size" class="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-2">Schlüsselgröße (Bits)</label>
<select id="ssl-key-size" class="input-modern w-full">
<option value="2048">2048 Bit</option>
<option value="4096" selected>4096 Bit (Empfohlen)</option>
<option value="8192">8192 Bit</option>
</select>
</div>
<div>
<label for="ssl-validity" class="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-2">Gültigkeitsdauer (Tage)</label>
<input type="number" id="ssl-validity" value="365" min="30" max="3650" class="input-modern w-full">
</div>
</div>
</div>
</div>
{% endif %}
<!-- Weitere Tabs können hier hinzugefügt werden -->
</div>
</div>
<script>
// SSL-Verwaltungsfunktionen
async function loadSSLInfo() {
const container = document.getElementById('ssl-info-container');
container.innerHTML = `
<div class="text-center py-8">
<div class="animate-spin rounded-full h-8 w-8 border-b-2 border-blue-600 mx-auto"></div>
<p class="mt-2 text-slate-600 dark:text-slate-400">Lade Zertifikatsinformationen...</p>
</div>
`;
try {
const response = await fetch('/api/ssl/info');
const data = await response.json();
if (data.exists) {
const cert = data.certificate;
const isExpired = cert.is_expired;
const daysUntilExpiry = cert.days_until_expiry;
container.innerHTML = `
<div class="space-y-4">
<div class="flex items-center justify-between p-4 bg-white dark:bg-slate-700 rounded-lg">
<span class="font-medium text-slate-900 dark:text-white">Status</span>
<span class="inline-flex items-center px-3 py-1 rounded-full text-xs font-medium ${isExpired ? 'bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-200' : daysUntilExpiry < 30 ? 'bg-yellow-100 text-yellow-800 dark:bg-yellow-900 dark:text-yellow-200' : 'bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-200'}">
${isExpired ? 'Abgelaufen' : daysUntilExpiry < 30 ? 'Läuft bald ab' : 'Gültig'}
</span>
</div>
<div class="p-4 bg-white dark:bg-slate-700 rounded-lg">
<div class="text-sm text-slate-600 dark:text-slate-400 mb-1">Gültig bis</div>
<div class="font-medium text-slate-900 dark:text-white">${cert.not_valid_after}</div>
</div>
<div class="p-4 bg-white dark:bg-slate-700 rounded-lg">
<div class="text-sm text-slate-600 dark:text-slate-400 mb-1">Verbleibende Tage</div>
<div class="font-medium text-slate-900 dark:text-white">${daysUntilExpiry} Tage</div>
</div>
<div class="p-4 bg-white dark:bg-slate-700 rounded-lg">
<div class="text-sm text-slate-600 dark:text-slate-400 mb-1">Schlüsselgröße</div>
<div class="font-medium text-slate-900 dark:text-white">${cert.key_size || 'Unbekannt'} Bit</div>
</div>
<div class="p-4 bg-white dark:bg-slate-700 rounded-lg">
<div class="text-sm text-slate-600 dark:text-slate-400 mb-1">Fingerprint (SHA256)</div>
<div class="font-mono text-xs text-slate-900 dark:text-white break-all">${cert.fingerprint}</div>
</div>
</div>
`;
} else {
container.innerHTML = `
<div class="text-center py-8">
<svg class="w-16 h-16 text-slate-400 mx-auto mb-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z" />
</svg>
<p class="text-slate-600 dark:text-slate-400">Kein SSL-Zertifikat gefunden</p>
<p class="text-sm text-slate-500 dark:text-slate-500 mt-2">Generieren Sie ein neues Zertifikat</p>
</div>
`;
}
} catch (error) {
container.innerHTML = `
<div class="text-center py-8">
<svg class="w-16 h-16 text-red-400 mx-auto mb-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
<p class="text-red-600 dark:text-red-400">Fehler beim Laden der Zertifikatsinformationen</p>
<p class="text-sm text-slate-500 dark:text-slate-500 mt-2">${error.message}</p>
</div>
`;
}
}
async function generateSSLCertificate() {
const keySize = document.getElementById('ssl-key-size').value;
const validity = document.getElementById('ssl-validity').value;
try {
const response = await fetch('/api/ssl/generate', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': document.querySelector('meta[name="csrf-token"]').getAttribute('content')
},
body: JSON.stringify({
key_size: parseInt(keySize),
validity_days: parseInt(validity)
})
});
const data = await response.json();
if (data.success) {
alert('SSL-Zertifikat erfolgreich generiert!');
loadSSLInfo();
} else {
alert('Fehler beim Generieren des SSL-Zertifikats: ' + data.error);
}
} catch (error) {
alert('Fehler beim Generieren des SSL-Zertifikats: ' + error.message);
}
}
async function installSSLCertificate() {
try {
const response = await fetch('/api/ssl/install', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': document.querySelector('meta[name="csrf-token"]').getAttribute('content')
}
});
const data = await response.json();
if (data.success) {
alert('SSL-Zertifikat erfolgreich im System installiert!');
} else {
alert('Fehler bei der Installation: ' + data.error);
}
} catch (error) {
alert('Fehler bei der Installation: ' + error.message);
}
}
async function copyToRaspberry() {
const host = prompt('Raspberry Pi Hostname:', 'raspberrypi');
if (!host) return;
const user = prompt('Benutzername:', 'pi');
if (!user) return;
try {
const response = await fetch('/api/ssl/copy-raspberry', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': document.querySelector('meta[name="csrf-token"]').getAttribute('content')
},
body: JSON.stringify({
host: host,
user: user
})
});
const data = await response.json();
if (data.success) {
alert('SSL-Zertifikat erfolgreich auf Raspberry Pi kopiert!');
} else {
alert('Fehler beim Kopieren: ' + data.error);
}
} catch (error) {
alert('Fehler beim Kopieren: ' + error.message);
}
}
async function validateSSLCertificate() {
try {
const response = await fetch('/api/ssl/validate');
const data = await response.json();
if (data.valid) {
alert('SSL-Zertifikat ist gültig!');
} else {
alert('SSL-Zertifikat ist ungültig oder läuft bald ab: ' + data.message);
}
} catch (error) {
alert('Fehler bei der Validierung: ' + error.message);
}
}
// SSL-Informationen beim Laden des SSL-Tabs laden
document.addEventListener('DOMContentLoaded', function() {
if (window.location.search.includes('tab=ssl')) {
loadSSLInfo();
}
});
</script>
{% endblock %}
{% block scripts %}

View File

@@ -79,8 +79,8 @@ class SSLCertificateManager:
"""Entfernt alte Zertifikate und veraltete Verzeichnisse"""
# Alte SSL-Verzeichnisse löschen
old_ssl_dirs = [
os.path.join(os.path.dirname(self.certs_dir), "instance", "ssl"),
os.path.join(os.path.dirname(self.certs_dir), "ssl")
os.path.join(os.path.dirname(os.path.dirname(self.certs_dir)), "app", "instance", "ssl"),
os.path.join(os.path.dirname(os.path.dirname(self.certs_dir)), "app", "certs")
]
for old_dir in old_ssl_dirs:

View File

@@ -1,171 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os
import datetime
import shutil
from pathlib import Path
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
import ipaddress
def generate_mercedes_certificate():
"""
Generiert ein vollständiges Mercedes-Benz-Zertifikat
mit korrekten Metadaten und alternativen Namen.
"""
print("Generiere Mercedes-Benz SSL-Zertifikat...")
# Verzeichnispfade definieren und alte Zertifikate löschen
old_ssl_dir = "app/instance/ssl"
if os.path.exists(old_ssl_dir):
print(f"Lösche alten SSL-Ordner: {old_ssl_dir}")
try:
shutil.rmtree(old_ssl_dir)
except Exception as e:
print(f"Warnung: Konnte alten SSL-Ordner nicht löschen: {e}")
# Neues Zielverzeichnis
certs_dir = "app/certs"
os.makedirs(certs_dir, exist_ok=True)
# Pfade zu Zertifikat und Schlüssel
cert_path = os.path.join(certs_dir, "myp.crt")
key_path = os.path.join(certs_dir, "myp.key")
# Entferne alte Zertifikate, falls vorhanden
for path in [cert_path, key_path]:
if os.path.exists(path):
os.remove(path)
try:
# Privaten Schlüssel mit 4096 Bit generieren (sicherer)
private_key = rsa.generate_private_key(
public_exponent=65537,
key_size=4096,
)
# Aktuelles Datum und Ablaufdatum (1 Jahr gültig)
now = datetime.datetime.now()
valid_until = now + datetime.timedelta(days=365)
# Liste aller möglichen Hostnamen/IPs
hostnames = [
"localhost",
"raspberrypi",
"m040tbaraspi001",
"m040tbaraspi001.de040.corpintra.net",
"mbag.corpintra.net",
"mbag.mb.corpintra.net"
]
# IP-Adressen (als String, werden später konvertiert)
ip_addresses = [
"127.0.0.1",
"192.168.0.101",
"192.168.0.102",
"192.168.0.103",
"192.168.0.104",
"192.168.0.105",
"192.168.0.106"
]
# Erweiterte Zertifikatsattribute für Mercedes-Benz
subject = issuer = x509.Name([
x509.NameAttribute(NameOID.COMMON_NAME, "raspberrypi"),
x509.NameAttribute(NameOID.ORGANIZATION_NAME, "Mercedes-Benz AG"),
x509.NameAttribute(NameOID.ORGANIZATIONAL_UNIT_NAME, "Werk 040 Berlin"),
x509.NameAttribute(NameOID.LOCALITY_NAME, "Berlin"),
x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, "Berlin"),
x509.NameAttribute(NameOID.COUNTRY_NAME, "DE"),
x509.NameAttribute(NameOID.EMAIL_ADDRESS, "admin@mercedes-benz.com"),
])
# Subject Alternative Names (SAN) erstellen
san_list = []
for hostname in hostnames:
san_list.append(x509.DNSName(hostname))
# IP-Adressen hinzufügen
for ip in ip_addresses:
san_list.append(x509.IPAddress(ipaddress.IPv4Address(ip)))
# 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(san_list),
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,
x509.oid.ExtendedKeyUsageOID.CODE_SIGNING
]), critical=False
).sign(private_key, hashes.SHA256())
# Zertifikat und Schlüssel speichern
with open(key_path, "wb") as f:
f.write(private_key.private_bytes(
encoding=Encoding.PEM,
format=PrivateFormat.TraditionalOpenSSL,
encryption_algorithm=NoEncryption()
))
with open(cert_path, "wb") as f:
f.write(cert.public_bytes(Encoding.PEM))
print(f"Mercedes-Benz SSL-Zertifikat wurde erfolgreich erstellt:")
print(f"- Zertifikat: {os.path.abspath(cert_path)}")
print(f"- Schlüssel: {os.path.abspath(key_path)}")
print(f"- Gültig bis: {valid_until.strftime('%d.%m.%Y')}")
print(f"- Hostnamen: {', '.join(hostnames)}")
print(f"- IP-Adressen: {', '.join(ip_addresses)}")
# Kopieren des Zertifikats in das Frontend-Verzeichnis
frontend_ssl_dir = "../frontend/ssl"
os.makedirs(frontend_ssl_dir, exist_ok=True)
shutil.copy2(cert_path, os.path.join(frontend_ssl_dir, "myp.crt"))
shutil.copy2(key_path, os.path.join(frontend_ssl_dir, "myp.key"))
print(f"Zertifikate wurden in das Frontend-Verzeichnis kopiert: {os.path.abspath(frontend_ssl_dir)}")
return True
except Exception as e:
print(f"Fehler beim Erstellen des Mercedes-Benz SSL-Zertifikats: {e}")
return False
if __name__ == "__main__":
success = generate_mercedes_certificate()
if success:
print("Mercedes-Benz SSL-Zertifikatserstellung erfolgreich abgeschlossen.")
else:
print("Fehler bei der Zertifikatserstellung!")
exit(1)

View File

@@ -1,261 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os
import datetime
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
import ipaddress
import argparse
def generate_ssl_certificate():
"""
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
os.makedirs(ssl_dir, exist_ok=True)
try:
# Privaten Schlüssel mit 4096 Bit generieren (sicherer)
private_key = rsa.generate_private_key(
public_exponent=65537,
key_size=4096,
)
# Aktuelles Datum und Ablaufdatum (1 Jahr gültig)
now = datetime.datetime.now()
valid_until = now + datetime.timedelta(days=365)
# Liste aller möglichen Hostnamen/IPs
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([
x509.NameAttribute(NameOID.COMMON_NAME, "raspberrypi"),
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")
])
# Subject Alternative Names (SAN) erstellen
san_list = []
for hostname in hostnames:
san_list.append(x509.DNSName(hostname))
# IP-Adressen hinzufügen
for ip in ip_addresses:
san_list.append(x509.IPAddress(ipaddress.IPv4Address(ip)))
# 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(san_list),
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())
# Zertifikat und Schlüssel speichern
with open(ssl_key_path, "wb") as f:
f.write(private_key.private_bytes(
encoding=Encoding.PEM,
format=PrivateFormat.TraditionalOpenSSL,
encryption_algorithm=NoEncryption()
))
with open(ssl_cert_path, "wb") as f:
f.write(cert.public_bytes(Encoding.PEM))
# Kopieren des Zertifikats in das Frontend-Verzeichnis
frontend_ssl_dir = "../frontend/ssl"
os.makedirs(frontend_ssl_dir, exist_ok=True)
import shutil
shutil.copy2(ssl_cert_path, os.path.join(frontend_ssl_dir, "myp.crt"))
shutil.copy2(ssl_key_path, os.path.join(frontend_ssl_dir, "myp.key"))
print(f"SSL-Zertifikat wurde erstellt:")
print(f"- Zertifikat: {ssl_cert_path}")
print(f"- Schlüssel: {ssl_key_path}")
print(f"- Kopiert nach: {frontend_ssl_dir}")
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
except Exception as e:
print(f"Fehler beim Erstellen des SSL-Zertifikats: {e}")
return False
def install_certificate_system():
"""
Installiert das Zertifikat im System-Zertifikatsspeicher (Windows).
Nur für Windows-Systeme.
"""
import platform
if platform.system() != "Windows":
print("Diese Funktion ist nur unter Windows verfügbar.")
return False
try:
import subprocess
import os
ssl_cert_path = os.path.abspath(os.path.join("app", "instance", "ssl", "myp.crt"))
# Prüfen, ob Datei existiert
if not os.path.exists(ssl_cert_path):
print(f"Zertifikat nicht gefunden unter: {ssl_cert_path}")
# Alternativen Pfad versuchen
alt_path = os.path.abspath(os.path.join("backend", "app", "instance", "ssl", "myp.crt"))
if os.path.exists(alt_path):
ssl_cert_path = alt_path
print(f"Verwende alternativen Pfad: {ssl_cert_path}")
else:
print("Zertifikat konnte nicht gefunden werden.")
return False
# Befehle zum Installieren des Zertifikats im Windows-Zertifikatsspeicher
commands = [
["certutil", "-addstore", "-f", "ROOT", ssl_cert_path],
["certutil", "-addstore", "-f", "CA", ssl_cert_path],
["certutil", "-addstore", "-f", "MY", ssl_cert_path]
]
for cmd in commands:
subprocess.run(cmd, check=True, capture_output=True)
print("Zertifikat wurde erfolgreich im System-Zertifikatsspeicher installiert.")
return True
except Exception as e:
print(f"Fehler bei der Installation des Zertifikats im System: {e}")
return False
def copy_to_raspberry():
"""
Kopiert das Zertifikat auf den Raspberry Pi.
Erfordert SSH-Zugriff auf den Raspberry Pi.
"""
try:
import subprocess
ssl_cert_path = os.path.abspath("app/instance/ssl/myp.crt")
ssl_key_path = os.path.abspath("app/instance/ssl/myp.key")
# Raspberry Pi-Zugangsdaten
raspberry_host = "raspberrypi"
raspberry_user = "pi"
raspberry_dest = "/home/pi/myp/ssl"
# Befehle zum Kopieren der Dateien auf den Raspberry Pi
scp_commands = [
["scp", ssl_cert_path, f"{raspberry_user}@{raspberry_host}:{raspberry_dest}/myp.crt"],
["scp", ssl_key_path, f"{raspberry_user}@{raspberry_host}:{raspberry_dest}/myp.key"]
]
# SSH-Befehl zum Erstellen des Verzeichnisses auf dem Raspberry Pi
ssh_command = ["ssh", f"{raspberry_user}@{raspberry_host}", f"mkdir -p {raspberry_dest}"]
# Verzeichnis auf dem Raspberry Pi erstellen
print(f"Erstelle Verzeichnis auf dem Raspberry Pi: {raspberry_dest}")
subprocess.run(ssh_command, check=True)
# Dateien kopieren
for cmd in scp_commands:
print(f"Kopiere {cmd[1]} nach {cmd[2]}")
subprocess.run(cmd, check=True)
print(f"Zertifikate wurden erfolgreich auf den Raspberry Pi kopiert nach {raspberry_dest}")
# Berechtigungen setzen
chmod_command = ["ssh", f"{raspberry_user}@{raspberry_host}", f"chmod 600 {raspberry_dest}/myp.key"]
subprocess.run(chmod_command, check=True)
# Zertifikat im System-Zertifikatsspeicher installieren
install_command = ["ssh", f"{raspberry_user}@{raspberry_host}", f"sudo cp {raspberry_dest}/myp.crt /usr/local/share/ca-certificates/ && sudo update-ca-certificates"]
subprocess.run(install_command, check=True)
print("Zertifikat wurde erfolgreich auf dem Raspberry Pi installiert und registriert.")
return True
except Exception as e:
print(f"Fehler beim Kopieren des Zertifikats auf den Raspberry Pi: {e}")
return False
if __name__ == "__main__":
print("=== MYP SSL-Zertifikatsgenerator ===")
# Kommandozeilenargumente parsen
parser = argparse.ArgumentParser(description='MYP SSL-Zertifikatsgenerator')
parser.add_argument('--no-install', action='store_true', help='Zertifikat nicht im System installieren')
parser.add_argument('--no-raspberry', action='store_true', help='Zertifikat nicht auf den Raspberry Pi kopieren')
parser.add_argument('--quiet', action='store_true', help='Keine Benutzerinteraktion')
args = parser.parse_args()
# Zertifikat generieren
cert_generated = generate_ssl_certificate()
if not cert_generated:
print("Generierung des Zertifikats fehlgeschlagen.")
exit(1)
# System-Installation des Zertifikats
if not args.no_install:
if args.quiet or input("Möchten Sie das Zertifikat im System-Zertifikatsspeicher installieren? (j/n): ").lower() == 'j':
install_certificate_system()
# Kopieren auf Raspberry Pi
if not args.no_raspberry:
if args.quiet or input("Möchten Sie das Zertifikat auf den Raspberry Pi kopieren? (j/n): ").lower() == 'j':
copy_to_raspberry()
print("Vorgang abgeschlossen.")