"""Fahrzeugbilder direkt aus der Oberfläche hochladen/löschen (Einstellungen -> Fahrzeugbilder, siehe BILDER_UPLOAD_SLOTS in audi-dashboard-app.js). Nur die festen, im Frontend fest verdrahteten Dateinamen sind erlaubt - eine Positivliste, damit ein manipulierter Dateiname aus dem Frontend niemals außerhalb von www/bilder/ schreiben kann (kein Pfad-Traversal über "../" oder absolute Pfade). Die Bytes werden unverändert unter dem erwarteten Namen abgelegt, unabhängig vom tatsächlichen Bildformat des Originalfotos (z. B. JPEG von einem iPhone unter einem ".webp"-Namen) - Browser stellen nach den tatsächlichen Bilddaten dar, nicht nach der Dateiendung, das funktioniert also trotzdem. Eine Größenbeschränkung gibt es bewusst nicht (Vorgabe: jede Fotogröße muss hochladbar sein). """ import base64 import io import os BILDER_ORDNER = "/config/www/bilder" ERLAUBTE_DATEINAMEN = { "seitenansicht.webp", "seitenansicht-winter.webp", "front-schraeg.webp", "frontansicht.webp", "heckansicht.webp", "cockpit.webp", "scheinwerfer.webp", "sitze.webp", "rad-sommer.webp", "rad-winter.webp", } def _pfad(dateiname): if dateiname not in ERLAUBTE_DATEINAMEN: return None return f"{BILDER_ORDNER}/{dateiname}" @service def audi_dashboard_bild_hochladen(dateiname=None, daten_base64=None): """Speichert ein aus der Oberfläche hochgeladenes Fahrzeugfoto unter einem der festen erwarteten Namen. Aufruf als pyscript.audi_dashboard_bild_hochladen.""" pfad = _pfad(dateiname) if not pfad or not daten_base64: log.warning(f"audi_dashboard: Bild-Upload abgelehnt (dateiname={dateiname})") return os.makedirs(BILDER_ORDNER, exist_ok=True) rohdaten = base64.b64decode(daten_base64) tmp = pfad + ".tmp" f = task.executor(io.open, tmp, "wb") f.write(rohdaten) f.close() os.replace(tmp, pfad) log.info(f"audi_dashboard: Fahrzeugbild gespeichert ({dateiname}, {len(rohdaten)} Bytes)") @service def audi_dashboard_bild_loeschen(dateiname=None): """Entfernt ein zuvor hochgeladenes Fahrzeugfoto wieder - die Ansicht fällt danach auf den Platzhalter zurück. Aufruf als pyscript.audi_dashboard_bild_loeschen.""" pfad = _pfad(dateiname) if not pfad: log.warning(f"audi_dashboard: Bild-Löschen abgelehnt (dateiname={dateiname})") return if os.path.exists(pfad): os.remove(pfad) log.info(f"audi_dashboard: Fahrzeugbild gelöscht ({dateiname})")