From c0877548ec37d21b4cf236f88dd6c06224edd3e6 Mon Sep 17 00:00:00 2001 From: Thomas Stallinger Date: Tue, 25 Aug 2026 09:01:53 +0200 Subject: [PATCH] feat: personalisierte ISO-Volume-ID aus Organisationsname + Bau-Datum compute_iso_volid() sanitisiert den Organisationsnamen ISO9660-konform (Grossbuchstaben/Ziffern/Unterstrich, max. 32 Zeichen, NFKD-Fallback fuer Umlaute, 'ORG'-Fallback falls kein ASCII-Zeichen uebrig bleibt) und haengt das Bau-Datum (UTC) an. run_iso_build() reicht das Ergebnis als sechsten Parameter an build_customer_iso.sh durch, statt des bisher fest codierten 'TUXFLOTTE'-Labels. Co-Authored-By: Claude Sonnet 5 --- app.py | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/app.py b/app.py index 6fc78fc..8dc274a 100644 --- a/app.py +++ b/app.py @@ -4,9 +4,11 @@ import hashlib import hmac import json import os +import re import secrets import subprocess import threading +import unicodedata from uuid import UUID, uuid4 import psycopg @@ -2184,11 +2186,35 @@ def cleanup_old_iso_builds(organization_id: str, keep_build_id) -> None: (organization_id, keep_build_id), ) +def compute_iso_volid(organization_name: str) -> str: + """ + ISO9660-Volume-ID fuer eine personalisierte Kunden-ISO: Organisationsname + + Bau-Datum, damit ein gemountetes/im Dateimanager angezeigtes Medium + erkennbar ist, statt bei der festen generischen Bezeichnung zu bleiben. + ISO9660 erlaubt fuer die Primary-Volume-Descriptor-Volume-ID nur + Grossbuchstaben/Ziffern/Unterstrich und maximal 32 Zeichen - Umlaute + u.ae. werden per NFKD-Normalisierung auf ihr ASCII-Grundzeichen + reduziert (z.B. "Groesse" statt Wegfall), alles andere zu "_" + zusammengefasst. Faellt bei einem Namen ohne jedes ASCII-Zeichen (z.B. + rein kyrillisch/chinesisch) auf "ORG" zurueck statt eine leere + Volume-ID zu erzeugen. + """ + ascii_only = unicodedata.normalize("NFKD", organization_name).encode("ascii", "ignore").decode("ascii") + sanitized = re.sub(r"[^A-Za-z0-9]+", "_", ascii_only).strip("_").upper() + date_suffix = datetime.now(timezone.utc).strftime("%Y%m%d") + max_name_len = 32 - 1 - len(date_suffix) # 32 - "_" - "YYYYMMDD" + sanitized = sanitized[:max_name_len].rstrip("_") or "ORG" + return f"{sanitized}_{date_suffix}" + + def run_iso_build(build_id, organization_id: str, activation_code: str, wifi_ssid: str | None, wifi_psk: str | None) -> None: output_path = ISO_BUILD_OUTPUT_DIR / f"{build_id}.iso" update_iso_build(build_id, status="running", mark_started=True) + organization = fetch_organization(organization_id) + volid = compute_iso_volid(organization["name"] if organization else "TUXFLOTTE") + try: result = subprocess.run( [ @@ -2199,6 +2225,7 @@ def run_iso_build(build_id, organization_id: str, activation_code: str, wifi_ssi activation_code, wifi_ssid or "", wifi_psk or "", + volid, ], cwd=TUXFLOTTE_INSTALLER_DIR, capture_output=True,