diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..7a73a41 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,2 @@ +{ +} \ No newline at end of file diff --git a/app.js b/app.js index 4775cfb..b29641a 100644 --- a/app.js +++ b/app.js @@ -5,33 +5,56 @@ const loginBtn = document.getElementById("login-btn"); const loginStatus = document.getElementById("login-status"); const userDisplay = document.getElementById("user-display"); -loginBtn.addEventListener("click", () => { +loginBtn.addEventListener("click", async () => { const user = document.getElementById("username").value.trim(); const pass = document.getElementById("password").value.trim(); - const found = USERS.find(u => u.username === user && u.password === pass); + if (!user || !pass) { + loginStatus.textContent = "Bitte Dienstkennung und Passwort eingeben."; + return; + } loginStatus.textContent = "Authentifizierung läuft…"; - setTimeout(() => { - if (!found) { - loginStatus.textContent = "Zugang verweigert – ungültige Anmeldedaten."; - return; - } + // Kurze Verzögerung für realistischen Effekt + await new Promise(r => setTimeout(r, 800)); + + const found = await authenticateUser(user, pass); + + if (!found) { + loginStatus.textContent = "Zugang verweigert – ungültige Anmeldedaten."; + return; + } + + loginScreen.style.display = "none"; + app.style.display = "flex"; - loginScreen.style.display = "none"; - app.style.display = "flex"; + userDisplay.textContent = found.username.toUpperCase(); - userDisplay.textContent = found.username.toUpperCase(); + document.getElementById("audit-log").textContent = + "Zugriff protokolliert – " + + new Date().toLocaleString("de-DE") + + " – Benutzer: " + + found.username; - document.getElementById("audit-log").textContent = - "Zugriff protokolliert – " + - new Date().toLocaleString("de-DE") + - " – Benutzer: " + - found.username; + loadAndRender(); +}); - loadAndRender(); - }, 700); +// LOGOUT +document.getElementById("logout-btn").addEventListener("click", () => { + app.style.display = "none"; + loginScreen.style.display = "flex"; + document.getElementById("username").value = ""; + document.getElementById("password").value = ""; + loginStatus.textContent = ""; +}); + +// Enter-Taste im Login +document.getElementById("password").addEventListener("keydown", (e) => { + if (e.key === "Enter") loginBtn.click(); +}); +document.getElementById("username").addEventListener("keydown", (e) => { + if (e.key === "Enter") loginBtn.click(); }); // LOCAL STORAGE PERSONS diff --git a/index.html b/index.html index ffda592..5fcd073 100644 --- a/index.html +++ b/index.html @@ -2,31 +2,49 @@ + POLIS – Polizei Informationssystem Hessen +
+
+ - +

POLIS

+ -

POLIS // Zugriffskontrolle

+ - +
@@ -39,29 +57,52 @@

POLIS // Zugriffskontrolle

class="topbar-logo" alt="Polizei Hessen Logo" > - - Polizei-Informationsdatenbank Hessen // Intern +
+ + Polizei-Informationsdatenbank Hessen // Klassifiziert +
- - VERBUNDEN +
+ VERBUNDEN + VERSCHLÜSSELT +
+
+ + +
+
@@ -71,8 +112,11 @@

Module

- - +
+ + +
+
@@ -82,6 +126,7 @@

Module

+
@@ -89,79 +134,94 @@

Module

-

Personen – Trefferliste

- - - - - - - - - - - -
IDNameGeburtsdatumStatusRegion
+

Personen – Trefferliste

+
+ + + + + + + + + + + +
IDNameGeburtsdatumStatusRegion
+
-

Personen – Details

+

Personen – Details

-

Bitte einen Datensatz aus der Liste auswählen.

+
+ +

Bitte einen Datensatz aus der Liste auswählen.

+
diff --git a/style.css b/style.css index 0bff615..139b041 100644 --- a/style.css +++ b/style.css @@ -2,15 +2,16 @@ box-sizing: border-box; margin: 0; padding: 0; - font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; + font-family: 'Segoe UI', system-ui, -apple-system, sans-serif; } body { - background: #05070b; + background: #0a0e1a; color: #e5e7eb; + overflow: hidden; } -/* LOGIN */ +/* ===== LOGIN ===== */ .login-screen { position: fixed; @@ -18,73 +19,142 @@ body { display: flex; align-items: center; justify-content: center; - background: radial-gradient(circle at top, #111827, #020617); + background: linear-gradient(135deg, #0a0e1a 0%, #1a1f3a 50%, #0a0e1a 100%); +} + +.login-screen::before { + content: ''; + position: absolute; + inset: 0; + background: url('data:image/svg+xml,'); + opacity: 0.5; } .login-box { - background: #020617; - border: 1px solid #1f2937; - padding: 2rem 2.5rem; - width: 360px; - box-shadow: 0 0 40px rgba(0,0,0,0.7); + position: relative; + background: rgba(10, 14, 26, 0.9); + border: 1px solid rgba(59, 130, 246, 0.3); + padding: 2.5rem 3rem; + width: 400px; + box-shadow: 0 0 60px rgba(59, 130, 246, 0.1), 0 0 120px rgba(0,0,0,0.5); text-align: center; - border-radius: 6px; + border-radius: 12px; + backdrop-filter: blur(20px); +} + +.login-header { + margin-bottom: 1.5rem; } .login-logo { - width: 100%; + width: 80%; + max-width: 280px; margin-bottom: 1rem; + border-radius: 8px; +} + +.login-badge { + display: inline-block; + padding: 0.25rem 1rem; + background: rgba(239, 68, 68, 0.15); + border: 1px solid rgba(239, 68, 68, 0.4); + color: #ef4444; + font-size: 0.7rem; + font-weight: 700; + letter-spacing: 0.2em; border-radius: 4px; } .login-box h1 { - font-size: 1.2rem; - margin-bottom: 1.5rem; - letter-spacing: 0.12em; - color: #60a5fa; + font-size: 1.8rem; + margin-bottom: 0.5rem; + letter-spacing: 0.15em; + color: #3b82f6; + font-weight: 800; } -.login-box label { - display: block; - margin-top: 0.75rem; - margin-bottom: 0.25rem; +.login-subtitle { + font-size: 0.8rem; + color: #6b7280; + margin-bottom: 2rem; + line-height: 1.5; +} + +.login-form { + display: flex; + flex-direction: column; + gap: 0.75rem; +} + +.input-group { + position: relative; + display: flex; + align-items: center; +} + +.input-group i { + position: absolute; + left: 12px; + color: #6b7280; font-size: 0.85rem; - color: #9ca3af; - text-align: left; } -.login-box input { +.input-group input { width: 100%; - padding: 0.5rem 0.6rem; - background: #020617; - border: 1px solid #374151; + padding: 0.75rem 0.75rem 0.75rem 2.5rem; + background: rgba(15, 23, 42, 0.8); + border: 1px solid #1e293b; color: #e5e7eb; - border-radius: 4px; + border-radius: 8px; + font-size: 0.9rem; + transition: border-color 0.2s, box-shadow 0.2s; +} + +.input-group input:focus { + outline: none; + border-color: #3b82f6; + box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1); } .login-box button { - margin-top: 1rem; + margin-top: 0.5rem; width: 100%; - padding: 0.6rem; - background: #2563eb; + padding: 0.75rem; + background: linear-gradient(135deg, #2563eb, #1d4ed8); border: none; color: white; font-weight: 600; + font-size: 0.9rem; cursor: pointer; - border-radius: 4px; + border-radius: 8px; + transition: transform 0.1s, box-shadow 0.2s; } .login-box button:hover { - background: #1d4ed8; + transform: translateY(-1px); + box-shadow: 0 4px 12px rgba(37, 99, 235, 0.4); +} + +.login-box button:active { + transform: translateY(0); } .login-status { - margin-top: 0.75rem; + margin-top: 1rem; font-size: 0.8rem; - color: #9ca3af; + color: #f97316; + min-height: 1.2em; +} + +.login-footer { + margin-top: 1.5rem; + font-size: 0.7rem; + color: #ef4444; + opacity: 0.7; } -/* APP LAYOUT */ + +/* ===== APP LAYOUT ===== */ .app { height: 100vh; @@ -93,55 +163,108 @@ body { } .topbar { - height: 56px; - background: #020617; - border-bottom: 1px solid #111827; + height: 60px; + background: rgba(10, 14, 26, 0.95); + border-bottom: 1px solid rgba(59, 130, 246, 0.15); display: flex; align-items: center; justify-content: space-between; padding: 0 1.5rem; + backdrop-filter: blur(10px); } .topbar-left { display: flex; align-items: center; + gap: 1rem; } .topbar-logo { - height: 40px; - margin-right: 1rem; - border-radius: 4px; + height: 42px; + border-radius: 6px; +} + +.topbar-brand { + display: flex; + flex-direction: column; } .logo { - font-weight: 700; + font-weight: 800; letter-spacing: 0.2em; - color: #60a5fa; - margin-right: 0.75rem; + color: #3b82f6; + font-size: 1.1rem; } .subtitle { - font-size: 0.8rem; - color: #9ca3af; + font-size: 0.7rem; + color: #6b7280; + letter-spacing: 0.05em; } .topbar-right { display: flex; align-items: center; - gap: 0.75rem; + gap: 1rem; +} + +.topbar-status { + display: flex; + gap: 0.5rem; +} + +.topbar-user { + display: flex; + align-items: center; + gap: 0.5rem; font-size: 0.85rem; + color: #94a3b8; + padding: 0.4rem 0.75rem; + background: rgba(30, 41, 59, 0.5); + border-radius: 6px; + border: 1px solid #1e293b; +} + +.btn-logout { + background: rgba(239, 68, 68, 0.1); + border: 1px solid rgba(239, 68, 68, 0.3); + color: #ef4444; + padding: 0.5rem 0.6rem; + border-radius: 6px; + cursor: pointer; + transition: background 0.2s; +} + +.btn-logout:hover { + background: rgba(239, 68, 68, 0.2); } .badge { - padding: 0.15rem 0.5rem; - border-radius: 999px; - font-size: 0.7rem; + padding: 0.2rem 0.6rem; + border-radius: 6px; + font-size: 0.65rem; + font-weight: 600; + letter-spacing: 0.05em; border: 1px solid; + display: flex; + align-items: center; + gap: 0.3rem; +} + +.badge i { + font-size: 0.5rem; } .badge-green { - border-color: #22c55e; + border-color: rgba(34, 197, 94, 0.4); color: #22c55e; + background: rgba(34, 197, 94, 0.08); +} + +.badge-blue { + border-color: rgba(59, 130, 246, 0.4); + color: #3b82f6; + background: rgba(59, 130, 246, 0.08); } .layout { @@ -150,66 +273,107 @@ body { min-height: 0; } -/* SIDEBAR */ + +/* ===== SIDEBAR ===== */ .sidebar { - width: 220px; - background: #020617; - border-right: 1px solid #111827; - padding: 1rem; + width: 240px; + background: rgba(10, 14, 26, 0.95); + border-right: 1px solid rgba(59, 130, 246, 0.1); + padding: 1.25rem; display: flex; flex-direction: column; justify-content: space-between; } +.sidebar-top {} + .sidebar h2 { - font-size: 0.9rem; + font-size: 0.75rem; text-transform: uppercase; - letter-spacing: 0.12em; + letter-spacing: 0.15em; color: #6b7280; - margin-bottom: 0.75rem; + margin-bottom: 1rem; + display: flex; + align-items: center; + gap: 0.5rem; } .sidebar ul { list-style: none; + display: flex; + flex-direction: column; + gap: 0.25rem; } .sidebar li { - padding: 0.4rem 0.5rem; - font-size: 0.9rem; - color: #e5e7eb; + padding: 0.6rem 0.75rem; + font-size: 0.85rem; + color: #94a3b8; cursor: pointer; - border-radius: 0.25rem; + border-radius: 8px; + display: flex; + align-items: center; + gap: 0.6rem; + transition: all 0.15s; +} + +.sidebar li i { + width: 18px; + text-align: center; + font-size: 0.8rem; } .sidebar li:hover { - background: #111827; + background: rgba(59, 130, 246, 0.08); + color: #e5e7eb; } .sidebar li.active { - background: #1f2937; + background: rgba(59, 130, 246, 0.15); + color: #3b82f6; + font-weight: 600; + border: 1px solid rgba(59, 130, 246, 0.2); } .sidebar-footer { + padding-top: 1rem; + border-top: 1px solid #1e293b; +} + +.audit-header { font-size: 0.75rem; color: #6b7280; + margin-bottom: 0.4rem; + display: flex; + align-items: center; + gap: 0.4rem; +} + +.sidebar-footer small { + font-size: 0.7rem; + color: #475569; + line-height: 1.4; } -/* MAIN */ + +/* ===== MAIN CONTENT ===== */ .main { flex: 1; - padding: 1rem 1.5rem; + padding: 1.25rem; display: flex; flex-direction: column; gap: 1rem; + overflow-y: auto; + background: #0d1117; } .search-section { - background: #020617; - border: 1px solid #111827; - padding: 0.75rem 1rem; - border-radius: 0.25rem; + background: rgba(10, 14, 26, 0.8); + border: 1px solid #1e293b; + padding: 1rem 1.25rem; + border-radius: 10px; } .search-row { @@ -217,183 +381,313 @@ body { gap: 0.5rem; } -.search-row input { +.search-input-wrapper { flex: 1; - padding: 0.5rem 0.6rem; - background: #020617; - border: 1px solid #374151; + position: relative; + display: flex; + align-items: center; +} + +.search-input-wrapper i { + position: absolute; + left: 12px; + color: #6b7280; +} + +.search-input-wrapper input { + width: 100%; + padding: 0.65rem 0.75rem 0.65rem 2.5rem; + background: rgba(15, 23, 42, 0.8); + border: 1px solid #1e293b; color: #e5e7eb; - border-radius: 4px; + border-radius: 8px; + font-size: 0.85rem; + transition: border-color 0.2s; +} + +.search-input-wrapper input:focus { + outline: none; + border-color: #3b82f6; } .search-row button { - padding: 0.5rem 0.9rem; - background: #2563eb; + padding: 0.65rem 1.25rem; + background: linear-gradient(135deg, #2563eb, #1d4ed8); border: none; color: white; - font-size: 0.9rem; + font-size: 0.85rem; + font-weight: 600; cursor: pointer; - border-radius: 4px; + border-radius: 8px; + display: flex; + align-items: center; + gap: 0.4rem; + transition: transform 0.1s; } .search-row button:hover { - background: #1d4ed8; + transform: translateY(-1px); } .filters-row { - margin-top: 0.5rem; + margin-top: 0.75rem; + display: flex; + align-items: center; + gap: 1rem; } .filters-row select { - padding: 0.35rem 0.5rem; - background: #020617; - border: 1px solid #374151; + padding: 0.4rem 0.75rem; + background: rgba(15, 23, 42, 0.8); + border: 1px solid #1e293b; color: #e5e7eb; - font-size: 0.85rem; - border-radius: 4px; + font-size: 0.8rem; + border-radius: 6px; +} + +.result-count { + font-size: 0.75rem; + color: #6b7280; } -/* CONTENT */ + +/* ===== CONTENT GRID ===== */ .content { display: grid; - grid-template-columns: 2fr 1.3fr; + grid-template-columns: 1.8fr 1.2fr; gap: 1rem; + flex: 1; min-height: 0; } .results, .details { - background: #020617; - border: 1px solid #111827; - border-radius: 0.25rem; - padding: 0.75rem 1rem; + background: rgba(10, 14, 26, 0.8); + border: 1px solid #1e293b; + border-radius: 10px; + padding: 1rem 1.25rem; display: flex; flex-direction: column; min-height: 0; + overflow: hidden; } .results h2, .details h2 { - font-size: 0.9rem; + font-size: 0.8rem; text-transform: uppercase; - letter-spacing: 0.12em; + letter-spacing: 0.1em; color: #6b7280; - margin-bottom: 0.5rem; + margin-bottom: 0.75rem; + display: flex; + align-items: center; + gap: 0.5rem; + padding-bottom: 0.75rem; + border-bottom: 1px solid #1e293b; +} + +.table-wrapper { + overflow-y: auto; + flex: 1; } .results table { width: 100%; border-collapse: collapse; - font-size: 0.85rem; + font-size: 0.8rem; } .results thead { - background: #020617; - border-bottom: 1px solid #111827; + position: sticky; + top: 0; + background: #0a0e1a; + z-index: 1; } -.results th, .results td { - padding: 0.35rem 0.25rem; +.results th { + padding: 0.5rem 0.5rem; text-align: left; + color: #6b7280; + font-weight: 600; + font-size: 0.7rem; + text-transform: uppercase; + letter-spacing: 0.05em; + border-bottom: 1px solid #1e293b; +} + +.results td { + padding: 0.5rem 0.5rem; + text-align: left; + border-bottom: 1px solid rgba(30, 41, 59, 0.5); } .results tbody tr { cursor: pointer; + transition: background 0.1s; } -.results tbody tr:nth-child(even) { - background: #020617; +.results tbody tr:hover { + background: rgba(59, 130, 246, 0.06); } -.results tbody tr:hover { - background: #111827; +.results tbody tr:active { + background: rgba(59, 130, 246, 0.12); } .status-pill { - padding: 0.1rem 0.4rem; - border-radius: 999px; - font-size: 0.7rem; + padding: 0.15rem 0.5rem; + border-radius: 6px; + font-size: 0.65rem; + font-weight: 600; + letter-spacing: 0.03em; border: 1px solid; } .status-AKTIV { - border-color: #60a5fa; + border-color: rgba(59, 130, 246, 0.4); color: #60a5fa; + background: rgba(59, 130, 246, 0.08); } .status-GESUCHT { - border-color: #f97316; + border-color: rgba(249, 115, 22, 0.4); color: #f97316; + background: rgba(249, 115, 22, 0.08); } .status-ARCHIVIERT { - border-color: #6b7280; - color: #6b7280; + border-color: rgba(107, 114, 128, 0.4); + color: #9ca3af; + background: rgba(107, 114, 128, 0.08); } -.details-content p { + +/* ===== DETAILS PANEL ===== */ + +.details { + overflow-y: auto; +} + +.empty-state { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + padding: 3rem 1rem; + color: #475569; +} + +.empty-state i { + font-size: 2rem; + margin-bottom: 0.75rem; + opacity: 0.5; +} + +.empty-state p { font-size: 0.85rem; - margin-bottom: 0.25rem; } -.details-content .label { - font-size: 0.75rem; - text-transform: uppercase; - letter-spacing: 0.12em; - color: #6b7280; - margin-top: 0.5rem; +.details-content { + animation: fadeIn 0.2s ease; } -/* BILDER */ +@keyframes fadeIn { + from { opacity: 0; transform: translateY(4px); } + to { opacity: 1; transform: translateY(0); } +} .details-content img { width: 100%; - border-radius: 6px; + border-radius: 8px; margin-bottom: 1rem; + border: 1px solid #1e293b; +} + +.details-content .label { + font-size: 0.65rem; + text-transform: uppercase; + letter-spacing: 0.12em; + color: #6b7280; + margin-top: 0.75rem; + font-weight: 600; +} + +.details-content p { + font-size: 0.85rem; + margin-top: 0.15rem; + color: #e5e7eb; } .result-photo { - width: 40px; - height: 40px; + width: 36px; + height: 36px; object-fit: cover; - border-radius: 4px; + border-radius: 6px; margin-right: 0.5rem; vertical-align: middle; + border: 1px solid #1e293b; } -/* ADMIN PANEL */ +/* ===== ADMIN PANEL ===== */ .admin-panel { - background: #020617; - border: 1px solid #111827; - padding: 1rem; - margin-top: 1rem; - border-radius: 0.25rem; + background: rgba(10, 14, 26, 0.8); + border: 1px solid #1e293b; + padding: 1.5rem; + margin-top: 0.5rem; + border-radius: 10px; } .admin-panel h2 { - font-size: 0.9rem; + font-size: 0.85rem; text-transform: uppercase; color: #6b7280; - margin-bottom: 0.75rem; + margin-bottom: 1.25rem; + display: flex; + align-items: center; + gap: 0.5rem; + letter-spacing: 0.08em; +} + +.admin-grid { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 1rem; +} + +.admin-field { + display: flex; + flex-direction: column; +} + +.admin-field.full-width { + grid-column: 1 / -1; } .admin-panel label { - display: block; - margin-top: 0.5rem; - font-size: 0.8rem; - color: #9ca3af; + font-size: 0.75rem; + color: #94a3b8; + margin-bottom: 0.3rem; + font-weight: 500; } .admin-panel input, .admin-panel select, .admin-panel textarea { width: 100%; - margin-top: 0.25rem; - padding: 0.4rem; - background: #020617; - border: 1px solid #374151; + padding: 0.6rem 0.75rem; + background: rgba(15, 23, 42, 0.8); + border: 1px solid #1e293b; color: #e5e7eb; - border-radius: 4px; + border-radius: 8px; + font-size: 0.85rem; + transition: border-color 0.2s; +} + +.admin-panel input:focus, +.admin-panel select:focus, +.admin-panel textarea:focus { + outline: none; + border-color: #3b82f6; } .admin-panel textarea { @@ -402,44 +696,55 @@ body { } .admin-panel button { - margin-top: 1rem; + margin-top: 1.25rem; width: 100%; - padding: 0.6rem; - background: #2563eb; + padding: 0.75rem; + background: linear-gradient(135deg, #2563eb, #1d4ed8); border: none; color: white; + font-weight: 600; + font-size: 0.9rem; cursor: pointer; - border-radius: 4px; + border-radius: 8px; + display: flex; + align-items: center; + justify-content: center; + gap: 0.5rem; + transition: transform 0.1s; } .admin-panel button:hover { - background: #1d4ed8; + transform: translateY(-1px); } -/* MAP VIEW */ + +/* ===== MAP VIEW ===== */ .map-view { grid-column: 1 / span 2; - background: #020617; - border: 1px solid #111827; - border-radius: 0.25rem; - padding: 0.75rem 1rem; + background: rgba(10, 14, 26, 0.8); + border: 1px solid #1e293b; + border-radius: 10px; + padding: 1rem 1.25rem; } .map-view h2 { - font-size: 0.9rem; + font-size: 0.8rem; text-transform: uppercase; - letter-spacing: 0.12em; + letter-spacing: 0.1em; color: #6b7280; - margin-bottom: 0.5rem; + margin-bottom: 0.75rem; + display: flex; + align-items: center; + gap: 0.5rem; } .map-container { width: 100%; - height: 350px; - border-radius: 4px; + height: 400px; + border-radius: 8px; overflow: hidden; - margin-bottom: 0.5rem; + border: 1px solid #1e293b; } .map-container iframe { @@ -447,34 +752,71 @@ body { height: 100%; } -.map-hint { - font-size: 0.8rem; - color: #9ca3af; +/* ===== SCROLLBAR ===== */ + +::-webkit-scrollbar { + width: 6px; } -/* UTILS */ +::-webkit-scrollbar-track { + background: transparent; +} + +::-webkit-scrollbar-thumb { + background: #1e293b; + border-radius: 3px; +} + +::-webkit-scrollbar-thumb:hover { + background: #334155; +} + +/* ===== UTILS ===== */ .hidden { display: none !important; } -/* RESPONSIVE */ +/* ===== RESPONSIVE ===== */ -@media (max-width: 900px) { +@media (max-width: 1100px) { .content { grid-template-columns: 1fr; } + .map-view { + grid-column: 1; + } } -@media (max-width: 700px) { +@media (max-width: 768px) { .layout { flex-direction: column; } .sidebar { + width: 100%; flex-direction: row; align-items: center; - width: 100%; border-right: none; - border-bottom: 1px solid #111827; + border-bottom: 1px solid #1e293b; + padding: 0.75rem 1rem; + } + .sidebar-top { + display: flex; + align-items: center; + gap: 1rem; + width: 100%; + } + .sidebar h2 { + display: none; + } + .sidebar ul { + flex-direction: row; + gap: 0.25rem; + } + .sidebar-footer { + display: none; + } + .topbar-status { + display: none; } } diff --git a/users.js b/users.js index 6f30990..706a994 100644 --- a/users.js +++ b/users.js @@ -1,5 +1,49 @@ -const USERS = [ - { username: "Hessen7504", password: "cobra11" }, - { username: "Hessen3840", password: "cobra111" }, - { username: "admin", password: "rootaccess" } +// ============================================================ +// POLIS – Authentifizierungsmodul +// ============================================================ +// Zugangsdaten sind als SHA-256 Hashes gespeichert. +// Passwörter können NICHT im Klartext ausgelesen werden. +// Benutzer müssen ihre Zugangsdaten bereits kennen. +// ============================================================ + +const USERS_HASHED = [ + { + usernameHash: "5e98b64a2cfa94a131b215cd03c9c43fd4dc602acfb7d597480f27ce9a29f9e7", + passwordHash: "cb2a35ff149a556cf437b63692856294f409207d5d53dd6584c4cb0bb1ea0bd5", + role: "operator" + }, + { + usernameHash: "6644ae39e5f414cdbedf4b14694c3fdf4e8c932ada781d38dabc21a4ffa0ab20", + passwordHash: "96fa370bc7a55fb029e53a75d8eeec5cb98d10110cc5f1192e1ec5ad94f06d69", + role: "operator" + }, + { + usernameHash: "8c6976e5b5410415bde908bd4dee15dfb167a9c873fc4bb8a81f6f2ab448a918", + passwordHash: "778c78fa79d89cd2a93096b793485141f88f6eb44c18fdb78f0912997293373f", + role: "admin" + } ]; + +// SHA-256 Hash-Funktion (Web Crypto API) +async function hashSHA256(text) { + const encoder = new TextEncoder(); + const data = encoder.encode(text); + const hashBuffer = await crypto.subtle.digest("SHA-256", data); + const hashArray = Array.from(new Uint8Array(hashBuffer)); + return hashArray.map(b => b.toString(16).padStart(2, "0")).join(""); +} + +// Authentifizierung prüfen – gibt User-Objekt oder null zurück +async function authenticateUser(username, password) { + const uHash = await hashSHA256(username); + const pHash = await hashSHA256(password); + + const match = USERS_HASHED.find( + u => u.usernameHash === uHash && u.passwordHash === pHash + ); + + if (match) { + return { username: username, role: match.role }; + } + return null; +}