"feat: Implement Mercedes-Benz certificate generation"

This commit is contained in:
2025-05-26 11:24:36 +02:00
parent 7d4ec90d99
commit 8f416e441c
3 changed files with 283 additions and 95 deletions

View File

@@ -1,12 +1,27 @@
import os
import json
import secrets
from datetime import timedelta
from pathlib import Path
# Hardcodierte Konfiguration
SECRET_KEY = "7445630171969DFAC92C53CEC92E67A9CB2E00B3CB2F"
DATABASE_PATH = "../database/myp.db"
TAPO_USERNAME = "till.tomczak@mercedes-benz.com"
TAPO_PASSWORD = "744563017196A"
# Basisverzeichnis der Anwendung für relative Pfade
BASE_DIR = Path(__file__).resolve().parent.parent
PROJECT_ROOT = BASE_DIR.parent
# Laden von Umgebungsvariablen, falls vorhanden
def get_env_variable(var_name, default=None):
"""Umgebungsvariablen abrufen mit Fallback auf Default-Werte"""
return os.environ.get(var_name, default)
# Sichere Konfiguration - Verwende Umgebungsvariablen oder generiere Secret Key
SECRET_KEY = get_env_variable("MYP_SECRET_KEY", secrets.token_hex(24))
# Datenbankpfad mit korrekter relativer Pfadauflösung
DATABASE_PATH = os.path.join(PROJECT_ROOT, "database", "myp.db")
# Tapo-Zugangsdaten aus Umgebungsvariablen laden
TAPO_USERNAME = get_env_variable("MYP_TAPO_USERNAME", "")
TAPO_PASSWORD = get_env_variable("MYP_TAPO_PASSWORD", "")
# Drucker-Konfiguration
PRINTERS = {
@@ -19,28 +34,28 @@ PRINTERS = {
}
# Logging-Konfiguration
LOG_DIR = "logs"
LOG_DIR = os.path.join(PROJECT_ROOT, "logs")
LOG_SUBDIRS = ["app", "scheduler", "auth", "jobs", "printers", "errors"]
LOG_LEVEL = "INFO"
LOG_LEVEL = get_env_variable("MYP_LOG_LEVEL", "INFO")
LOG_FORMAT = "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
LOG_DATE_FORMAT = "%Y-%m-%d %H:%M:%S"
# Flask-Konfiguration
FLASK_HOST = "0.0.0.0"
FLASK_PORT = 443
FLASK_FALLBACK_PORT = 80
FLASK_DEBUG = True
SESSION_LIFETIME = timedelta(days=7)
FLASK_HOST = get_env_variable("MYP_FLASK_HOST", "0.0.0.0")
FLASK_PORT = int(get_env_variable("MYP_FLASK_PORT", 443))
FLASK_FALLBACK_PORT = int(get_env_variable("MYP_FLASK_FALLBACK_PORT", 80))
FLASK_DEBUG = get_env_variable("MYP_FLASK_DEBUG", "True").lower() in ("true", "1", "yes")
SESSION_LIFETIME = timedelta(days=int(get_env_variable("MYP_SESSION_DAYS", 7)))
# SSL-Konfiguration
SSL_ENABLED = True
SSL_CERT_PATH = "../certs/myp.crt"
SSL_KEY_PATH = "../certs/myp.key"
SSL_HOSTNAME = "raspberrypi"
SSL_ENABLED = get_env_variable("MYP_SSL_ENABLED", "True").lower() in ("true", "1", "yes")
SSL_CERT_PATH = os.path.join(PROJECT_ROOT, "certs", "myp.crt")
SSL_KEY_PATH = os.path.join(PROJECT_ROOT, "certs", "myp.key")
SSL_HOSTNAME = get_env_variable("MYP_SSL_HOSTNAME", "raspberrypi")
# Scheduler-Konfiguration
SCHEDULER_INTERVAL = 60 # Sekunden
SCHEDULER_ENABLED = True
SCHEDULER_INTERVAL = int(get_env_variable("MYP_SCHEDULER_INTERVAL", 60)) # Sekunden
SCHEDULER_ENABLED = get_env_variable("MYP_SCHEDULER_ENABLED", "True").lower() in ("true", "1", "yes")
# Datenbank-Konfiguration
DB_ENGINE = f"sqlite:///{DATABASE_PATH}"

View File

@@ -0,0 +1,172 @@
#!/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)
import shutil
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)