From 0635bb5b8a84163150af7a043bb298895548e3d9 Mon Sep 17 00:00:00 2001 From: patrick Date: Wed, 28 Oct 2026 22:24:22 +0100 Subject: [PATCH] =?UTF-8?q?feat(frontend):=20Ger=C3=A4te-ID-QR=20f=C3=BCr?= =?UTF-8?q?=20Ed25519-Kiosk=20+=20TLS-Warnung=20bei=20Bearer?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 5.5 --- frontend/src/pages/KioskDevicesPage.tsx | 69 ++++++++++++++++++++++--- 1 file changed, 63 insertions(+), 6 deletions(-) diff --git a/frontend/src/pages/KioskDevicesPage.tsx b/frontend/src/pages/KioskDevicesPage.tsx index 68b4157..98faba9 100644 --- a/frontend/src/pages/KioskDevicesPage.tsx +++ b/frontend/src/pages/KioskDevicesPage.tsx @@ -95,6 +95,16 @@ export function KioskDevicesPage() { QRCode.toDataURL(payload, { width: 260, margin: 2 }).then(setBearerQrDataUrl) }, [bearerResult]) + // Ed25519-Geräte-ID-Ergebnis (Kiosk-App scannt {url, device_id}) + const [deviceIdResult, setDeviceIdResult] = useState<{ deviceId: string; deviceName: string } | null>(null) + const [deviceIdQrDataUrl, setDeviceIdQrDataUrl] = useState('') + + useEffect(() => { + if (!deviceIdResult) { setDeviceIdQrDataUrl(''); return } + const payload = JSON.stringify({ url: `${window.location.origin}/api/v1`, device_id: deviceIdResult.deviceId }) + QRCode.toDataURL(payload, { width: 260, margin: 2 }).then(setDeviceIdQrDataUrl) + }, [deviceIdResult]) + // Edit modal const [editDevice, setEditDevice] = useState(null) const [editName, setEditName] = useState('') @@ -138,12 +148,13 @@ export function KioskDevicesPage() { }) setBearerResult({ token: res.token, deviceName: res.device.name }) } else { - await api.post('/kiosk/devices', { + const res = await api.post('/kiosk/devices', { name: createName.trim(), location: createLocation.trim() || null, public_key: createPublicKey.trim(), ip_whitelist: createIpWhitelist.trim() || null, }) + setDeviceIdResult({ deviceId: res.id, deviceName: res.name }) } setShowCreate(false) setCreateName('') @@ -415,14 +426,24 @@ export function KioskDevicesPage() { onClick={() => setCreateMode('bearer')} className={`flex-1 px-3 py-2 font-medium ${createMode === 'bearer' ? 'bg-blue-600 text-white' : 'bg-white text-gray-600 hover:bg-gray-50'}`} > - Android-Tablet (Bearer/VPN) + Android-Tablet (Bearer/VPN) ⚠ - {createMode === 'bearer' && ( + {createMode === 'ed25519' && (
- Kein Public Key nötig – nach dem Anlegen bekommst du ein Token - + QR-Code, den die Kiosk-App beim Einrichten scannen kann. - Setzt WireGuard-VPN mit fester Geräte-IP voraus. + Auch für Android-Tablets empfohlen (seit Security-Audit + 2026-09-10): Kiosk-App erzeugt selbst ein Schlüsselpaar und + zeigt den Public Key zum Einfügen hier an. Kein Token, keine + unbegrenzt gültigen Secrets. +
+ )} + {createMode === 'bearer' && ( +
+ ⚠ Nur mit echtem TLS/HTTPS auf dem Server verwenden. Ohne TLS + ist das Token unverschlüsselt mitschneidbar und unbegrenzt + gültig (Security-Audit 2026-09-10) – auf HTTP-Servern bitte + stattdessen „PC-Terminal (Ed25519)" nutzen, das Kiosk-Setup + unterstützt das jetzt auch für Tablets.
)}