Add raw GVL evidence storage and restore evidence purge UI
Dieser Commit ist enthalten in:
+16
-1
@@ -672,8 +672,23 @@ async function fetchOfficialGvlJson() {
|
||||
throw error;
|
||||
}
|
||||
|
||||
const rawBody = await response.text();
|
||||
const fetchedAt = new Date().toISOString();
|
||||
const contentType = response.headers.get("Content-Type");
|
||||
const rawGvlSha256 = await VendorGetGvlService.calculateRawGvlSha256(rawBody);
|
||||
const db = await openVendorGetDb();
|
||||
|
||||
await VendorGetGvlService.storeGvlRawEvidenceIfNew(db, {
|
||||
rawGvlSha256,
|
||||
sourceUrl: OFFICIAL_IAB_GVL_URL,
|
||||
fetchedAt,
|
||||
httpStatus: response.status,
|
||||
contentType,
|
||||
rawBody
|
||||
});
|
||||
|
||||
return {
|
||||
rawJson: await response.json(),
|
||||
rawJson: JSON.parse(rawBody),
|
||||
responseStatus: response.status
|
||||
};
|
||||
}
|
||||
|
||||
@@ -9,6 +9,47 @@ async function calculateGvlSnapshotSha256(rawJson) {
|
||||
.join("");
|
||||
}
|
||||
|
||||
async function calculateRawGvlSha256(rawBody) {
|
||||
const data = new TextEncoder().encode(rawBody);
|
||||
const hashBuffer = await crypto.subtle.digest("SHA-256", data);
|
||||
const hashArray = Array.from(new Uint8Array(hashBuffer));
|
||||
|
||||
return hashArray
|
||||
.map((byte) => byte.toString(16).padStart(2, "0"))
|
||||
.join("");
|
||||
}
|
||||
|
||||
function storeGvlRawEvidenceIfNew(db, rawEvidence) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const tx = db.transaction(["gvl_raw_evidence"], "readwrite");
|
||||
const rawEvidenceStore = tx.objectStore("gvl_raw_evidence");
|
||||
const getRequest = rawEvidenceStore.get(rawEvidence.rawGvlSha256);
|
||||
let result = null;
|
||||
|
||||
getRequest.onerror = () => reject(getRequest.error);
|
||||
|
||||
getRequest.onsuccess = () => {
|
||||
if (getRequest.result) {
|
||||
result = {
|
||||
stored: false,
|
||||
rawGvlSha256: rawEvidence.rawGvlSha256
|
||||
};
|
||||
return;
|
||||
}
|
||||
|
||||
rawEvidenceStore.add(rawEvidence);
|
||||
|
||||
result = {
|
||||
stored: true,
|
||||
rawGvlSha256: rawEvidence.rawGvlSha256
|
||||
};
|
||||
};
|
||||
|
||||
tx.onerror = () => reject(tx.error);
|
||||
tx.oncomplete = () => resolve(result);
|
||||
});
|
||||
}
|
||||
|
||||
async function buildGvlSnapshotRecord(rawJson, sourceUrl, fetchedAt) {
|
||||
const gvlJson = normalizeGvlSnapshotValueForMetadata(rawJson);
|
||||
|
||||
@@ -149,6 +190,8 @@ function countObjectEntries(value) {
|
||||
|
||||
globalThis.VendorGetGvlService = {
|
||||
calculateGvlSnapshotSha256,
|
||||
calculateRawGvlSha256,
|
||||
storeGvlRawEvidenceIfNew,
|
||||
buildGvlSnapshotRecord,
|
||||
storeGvlSnapshotIfNew,
|
||||
recordGvlSnapshotEvent,
|
||||
|
||||
@@ -175,3 +175,45 @@ button:disabled {
|
||||
cursor: default;
|
||||
opacity: 0.65;
|
||||
}
|
||||
|
||||
.confirm-modal {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
padding: 14px;
|
||||
background: rgba(15, 23, 42, 0.72);
|
||||
}
|
||||
|
||||
.confirm-modal[hidden] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.confirm-modal-panel {
|
||||
display: grid;
|
||||
gap: 10px;
|
||||
width: min(100%, 320px);
|
||||
padding: 12px;
|
||||
border: 1px solid #475569;
|
||||
border-radius: 6px;
|
||||
color: #e5edf5;
|
||||
background: #111827;
|
||||
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.35);
|
||||
}
|
||||
|
||||
.confirm-modal-panel h2 {
|
||||
margin: 0;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.confirm-modal-panel p {
|
||||
margin: 0;
|
||||
font-size: 12px;
|
||||
line-height: 1.4;
|
||||
color: #cbd5e1;
|
||||
}
|
||||
|
||||
.confirm-modal-actions {
|
||||
display: grid;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
@@ -66,11 +66,39 @@
|
||||
<button id="evidence-export-json-button" type="button">
|
||||
Export Evidence JSON
|
||||
</button>
|
||||
<button id="evidence-purge-unlocked-button" type="button">
|
||||
Ungesperrte Evidence-Daten löschen
|
||||
</button>
|
||||
<div id="evidence-export-json-status" class="retention-status" aria-live="polite"></div>
|
||||
<div id="evidence-retention-status" class="retention-status" aria-live="polite">
|
||||
Status wird geladen
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div
|
||||
id="evidence-purge-confirm-modal"
|
||||
class="confirm-modal"
|
||||
role="dialog"
|
||||
aria-modal="true"
|
||||
aria-labelledby="evidence-purge-confirm-title"
|
||||
hidden
|
||||
>
|
||||
<div class="confirm-modal-panel">
|
||||
<h2 id="evidence-purge-confirm-title">Evidence-Daten löschen</h2>
|
||||
<p>
|
||||
Ungesperrte Evidence-Daten wirklich löschen? Gesperrte
|
||||
DSGVO-Datensätze bleiben erhalten.
|
||||
</p>
|
||||
<div class="confirm-modal-actions">
|
||||
<button id="evidence-purge-cancel-button" type="button">
|
||||
Abbrechen
|
||||
</button>
|
||||
<button id="evidence-purge-confirm-button" type="button">
|
||||
Ungesperrte Daten löschen
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<script src="../core/settings-storage.js"></script>
|
||||
|
||||
@@ -16,6 +16,18 @@ const evidenceDashboardButton = document.getElementById(
|
||||
const evidenceExportJsonButton = document.getElementById(
|
||||
"evidence-export-json-button"
|
||||
);
|
||||
const evidencePurgeUnlockedButton = document.getElementById(
|
||||
"evidence-purge-unlocked-button"
|
||||
);
|
||||
const evidencePurgeConfirmModal = document.getElementById(
|
||||
"evidence-purge-confirm-modal"
|
||||
);
|
||||
const evidencePurgeCancelButton = document.getElementById(
|
||||
"evidence-purge-cancel-button"
|
||||
);
|
||||
const evidencePurgeConfirmButton = document.getElementById(
|
||||
"evidence-purge-confirm-button"
|
||||
);
|
||||
const evidenceExportJsonStatus = document.getElementById(
|
||||
"evidence-export-json-status"
|
||||
);
|
||||
@@ -69,6 +81,9 @@ document.addEventListener("DOMContentLoaded", async () => {
|
||||
});
|
||||
|
||||
evidenceExportJsonButton.addEventListener("click", exportEvidenceJsonFile);
|
||||
evidencePurgeUnlockedButton.addEventListener("click", openPurgeConfirmModal);
|
||||
evidencePurgeCancelButton.addEventListener("click", closePurgeConfirmModal);
|
||||
evidencePurgeConfirmButton.addEventListener("click", purgeUnlockedEvidence);
|
||||
});
|
||||
|
||||
async function renderSettings() {
|
||||
@@ -143,6 +158,48 @@ function renderEvidenceRetentionMessage(message) {
|
||||
evidenceRetentionStatus.textContent = message;
|
||||
}
|
||||
|
||||
function openPurgeConfirmModal() {
|
||||
evidencePurgeConfirmModal.hidden = false;
|
||||
evidencePurgeCancelButton.focus();
|
||||
}
|
||||
|
||||
function closePurgeConfirmModal() {
|
||||
evidencePurgeConfirmModal.hidden = true;
|
||||
evidencePurgeUnlockedButton.focus();
|
||||
}
|
||||
|
||||
async function purgeUnlockedEvidence() {
|
||||
closePurgeConfirmModal();
|
||||
evidencePurgeUnlockedButton.disabled = true;
|
||||
renderEvidenceRetentionMessage("Ungesperrte Evidence-Daten werden gelöscht...");
|
||||
|
||||
try {
|
||||
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 renderEvidenceRetentionStatus();
|
||||
renderEvidenceRetentionMessage(buildPurgeUnlockedSuccessMessage(result));
|
||||
} catch (error) {
|
||||
renderEvidenceRetentionMessage("Löschen fehlgeschlagen");
|
||||
console.warn("VendorGet-IV unlocked evidence purge failed", error);
|
||||
} finally {
|
||||
evidencePurgeUnlockedButton.disabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
function buildPurgeUnlockedSuccessMessage(result) {
|
||||
if (Number.isFinite(result.deletedCount)) {
|
||||
return `Ungesperrte Evidence-Daten gelöscht: ${result.deletedCount} Records`;
|
||||
}
|
||||
|
||||
return "Ungesperrte Evidence-Daten gelöscht";
|
||||
}
|
||||
|
||||
async function exportEvidenceJsonFile() {
|
||||
evidenceExportJsonButton.disabled = true;
|
||||
renderEvidenceExportJsonMessage("Export läuft…");
|
||||
|
||||
In neuem Issue referenzieren
Einen Benutzer sperren