"use strict"; const EVIDENCE_MAINTENANCE_SOURCE = "dashboard"; const EVIDENCE_MAINTENANCE_HEARTBEAT_MS = 5 * 1000; const dashboardStatus = document.getElementById("dashboard-status"); const totalCount = document.getElementById("total-count"); const lockedCount = document.getElementById("locked-count"); const unlockedCount = document.getElementById("unlocked-count"); const maintenanceWriteSuspend = document.getElementById( "maintenance-write-suspend" ); const maintenanceSource = document.getElementById("maintenance-source"); const maintenanceHeartbeat = document.getElementById("maintenance-heartbeat"); const maintenanceExpires = document.getElementById("maintenance-expires"); const lockAllButton = document.getElementById("lock-all-button"); const unlockAllButton = document.getElementById("unlock-all-button"); const gvlFetchOfficialButton = document.getElementById( "gvl-fetch-official-button" ); const gvlImportButton = document.getElementById("gvl-import-button"); const evidenceDeleteButton = document.getElementById("evidence-delete-button"); const adminStatus = document.getElementById("admin-status"); const gvlImportFileInput = document.createElement("input"); gvlImportFileInput.type = "file"; gvlImportFileInput.accept = ".json,application/json"; gvlImportFileInput.hidden = true; let evidenceMaintenanceHeartbeatId = null; const storeCells = { consent_states: document.getElementById("store-consent-states"), consent_events: document.getElementById("store-consent-events"), observed_requests: document.getElementById("store-observed-requests"), gvl_snapshots: document.getElementById("store-gvl-snapshots"), gvl_snapshot_events: document.getElementById("store-gvl-snapshot-events") }; document.addEventListener("DOMContentLoaded", async () => { document.body.appendChild(gvlImportFileInput); await startEvidenceMaintenanceMode(); evidenceMaintenanceHeartbeatId = setInterval(() => { void refreshEvidenceMaintenanceMode(); }, EVIDENCE_MAINTENANCE_HEARTBEAT_MS); lockAllButton.addEventListener("click", async () => { await handleLockAllClick(); }); unlockAllButton.addEventListener("click", async () => { await handleUnlockAllClick(); }); gvlFetchOfficialButton.addEventListener("click", async () => { await fetchOfficialGvl(); }); gvlImportButton.addEventListener("click", () => { gvlImportFileInput.value = ""; gvlImportFileInput.click(); }); gvlImportFileInput.addEventListener("change", async () => { const file = gvlImportFileInput.files?.[0] ?? null; if (!file) { return; } await importGvlFile(file); }); evidenceDeleteButton.addEventListener("click", async () => { await handleEvidenceDeleteClick(); }); await renderEvidenceStatus(); }); window.addEventListener("beforeunload", () => { endEvidenceMaintenanceMode(); }); window.addEventListener("pagehide", () => { endEvidenceMaintenanceMode(); }); async function startEvidenceMaintenanceMode() { try { const status = await sendEvidenceMaintenanceMessage( "start_evidence_maintenance_session" ); renderEvidenceMaintenanceStatus(status); } catch (error) { renderEvidenceMaintenanceUnavailable(); console.warn("VendorGet-IV maintenance start failed", error); } } async function refreshEvidenceMaintenanceMode() { try { const status = await sendEvidenceMaintenanceMessage( "refresh_evidence_maintenance_session" ); renderEvidenceMaintenanceStatus(status); } catch (error) { renderEvidenceMaintenanceUnavailable(); console.warn("VendorGet-IV maintenance heartbeat failed", error); } } function endEvidenceMaintenanceMode() { if (evidenceMaintenanceHeartbeatId !== null) { clearInterval(evidenceMaintenanceHeartbeatId); evidenceMaintenanceHeartbeatId = null; } void sendEvidenceMaintenanceMessage("end_evidence_maintenance_session").catch( (error) => { console.warn("VendorGet-IV maintenance end failed", error); } ); } async function sendEvidenceMaintenanceMessage(type) { const status = await browser.runtime.sendMessage({ type: type, payload: { source: EVIDENCE_MAINTENANCE_SOURCE } }); if (!status?.success) { throw new Error(status?.error ?? `${type}_failed`); } return status; } function renderEvidenceMaintenanceStatus(status) { maintenanceWriteSuspend.textContent = status.evidenceWriteSuspended ? "aktiv" : "inaktiv"; maintenanceSource.textContent = status.source ?? "-"; maintenanceHeartbeat.textContent = formatMaintenanceTimestamp( status.lastHeartbeatAt ); maintenanceExpires.textContent = formatMaintenanceTimestamp(status.expiresAt); } function renderEvidenceMaintenanceUnavailable() { maintenanceWriteSuspend.textContent = "unbekannt"; maintenanceSource.textContent = "-"; maintenanceHeartbeat.textContent = "-"; maintenanceExpires.textContent = "-"; } async function renderEvidenceStatus() { try { const status = await browser.runtime.sendMessage({ type: "get_evidence_retention_status" }); if (!status?.success) { throw new Error(status?.error ?? "get_evidence_retention_status_failed"); } totalCount.textContent = String(status.totalCount); lockedCount.textContent = String(status.lockedCount); unlockedCount.textContent = String(status.unlockedCount); renderStoreCounts(status.storeCounts ?? {}); renderStatusMessage("Evidence status loaded"); } catch (error) { renderStatusMessage("Evidence status could not be loaded"); console.warn("VendorGet-IV dashboard status failed", error); } } function renderStoreCounts(storeCounts) { for (const [storeName, cell] of Object.entries(storeCells)) { cell.textContent = String(storeCounts[storeName] ?? 0); } } async function fetchOfficialGvl() { gvlFetchOfficialButton.disabled = true; renderAdminStatus("Fetching official IAB GVL..."); try { const result = await browser.runtime.sendMessage({ type: "fetch_official_gvl" }); if (!result?.success) { throw new Error(result?.error ?? "official_gvl_fetch_failed"); } await renderEvidenceStatus(); renderAdminStatus( "Fetched successfully - " + `${result.alreadyKnown ? "already known" : "newly stored"} - ` + `vendorListVersion ${result.vendorListVersion ?? "n/a"} - ` + `sha256 ${shortenSha256(result.sha256)}` ); } catch (error) { renderAdminStatus("Official GVL fetch failed"); console.warn("VendorGet-IV official GVL fetch failed", error); } finally { gvlFetchOfficialButton.disabled = false; } } async function importGvlFile(file) { gvlImportButton.disabled = true; renderAdminStatus("Import läuft..."); try { const fileContent = await readFileAsText(file); const rawJson = JSON.parse(fileContent); if (!isGvlImportCandidate(rawJson)) { throw new Error("invalid_gvl_json"); } const result = await browser.runtime.sendMessage({ type: "gvl_import_json", payload: { rawJson: rawJson, sourceUrl: "local-file-import" } }); if (!result?.success) { throw new Error(result?.error ?? "gvl_import_failed"); } await renderEvidenceStatus(); renderAdminStatus( `${result.alreadyKnown ? "already known" : "imported"} - ` + `vendorListVersion ${result.vendorListVersion ?? "n/a"} - ` + `sha256 ${shortenSha256(result.sha256)}` ); } catch (error) { renderAdminStatus("Import fehlgeschlagen"); console.warn("VendorGet-IV GVL import failed", error); } finally { gvlImportButton.disabled = false; } } function readFileAsText(file) { return new Promise((resolve, reject) => { const reader = new FileReader(); reader.onerror = () => reject(reader.error); reader.onload = () => resolve(reader.result); reader.readAsText(file); }); } function isGvlImportCandidate(value) { return ( value && typeof value === "object" && !Array.isArray(value) && value.vendorListVersion !== undefined && value.vendors && typeof value.vendors === "object" && !Array.isArray(value.vendors) ); } async function handleEvidenceDeleteClick() { evidenceDeleteButton.disabled = true; try { const status = await getEvidenceRetentionStatus(); const confirmed = confirm( "Alle lokal gespeicherten VG-IV-Evidenzdaten wirklich löschen?" ); if (!confirmed) { renderAdminStatus("Löschung abgebrochen"); return; } if (status.lockedCount === 0) { await deleteAllEvidenceDatabase(); await renderEvidenceStatus(); renderAdminStatus("Evidenzdaten gelöscht"); return; } const deleteLockedRecords = confirm( `Achtung: ${status.lockedCount} Datensätze wurden als ` + "DSGVO-/DSAR-relevant markiert. Sollen auch diese Datensätze " + "wirklich gelöscht werden?" ); if (deleteLockedRecords) { await deleteAllEvidenceDatabase(); await renderEvidenceStatus(); renderAdminStatus("Evidenzdaten gelöscht"); return; } const result = await browser.runtime.sendMessage({ type: "purge_unlocked_evidence_records" }); if (!result?.success) { throw new Error(result?.error ?? "purge_unlocked_evidence_records_failed"); } await renderEvidenceStatus(); renderAdminStatus( `${result.deletedCount} Datensätze gelöscht, ` + `${result.keptLockedCount} gesperrte Datensätze behalten` ); } catch (error) { renderAdminStatus("Löschung fehlgeschlagen"); console.warn("VendorGet-IV evidence delete failed", error); } finally { evidenceDeleteButton.disabled = false; } } async function getEvidenceRetentionStatus() { const status = await browser.runtime.sendMessage({ type: "get_evidence_retention_status" }); if (!status?.success) { throw new Error(status?.error ?? "get_evidence_retention_status_failed"); } return status; } async function deleteAllEvidenceDatabase() { const result = await browser.runtime.sendMessage({ type: "delete_all_evidence_database" }); if (!result?.success) { throw new Error(result?.error ?? "delete_all_evidence_database_failed"); } } async function handleLockAllClick() { const confirmed = confirm( "Alle vorhandenen VG-IV-Evidenzdatensätze als DSGVO-/DSAR-relevant markieren?" ); if (!confirmed) { renderStatusMessage("Record lock update cancelled"); return; } await runRecordLockAction({ type: "lock_all_evidence_records", payload: { reason: "dsar_used", note: null } }); } async function handleUnlockAllClick() { const confirmed = confirm( "Alle VG-IV-Evidenzsperren wirklich entfernen?" ); if (!confirmed) { renderStatusMessage("Record lock update cancelled"); return; } await runRecordLockAction({ type: "unlock_all_evidence_records" }); } async function runRecordLockAction(message) { setRecordLockButtonsDisabled(true); try { const result = await browser.runtime.sendMessage(message); if (!result?.success) { throw new Error(result?.error ?? `${message.type}_failed`); } await renderEvidenceStatus(); } catch (error) { renderStatusMessage("Record lock update failed"); console.warn("VendorGet-IV dashboard record lock update failed", error); } finally { setRecordLockButtonsDisabled(false); } } function setRecordLockButtonsDisabled(disabled) { lockAllButton.disabled = disabled; unlockAllButton.disabled = disabled; } function renderStatusMessage(message) { dashboardStatus.textContent = message; } function renderAdminStatus(message) { adminStatus.textContent = message; } function shortenSha256(value) { if (!value) { return "n/a"; } return `${value.slice(0, 12)}...`; } function formatMaintenanceTimestamp(value) { if (!value) { return "-"; } return value; }