Commits vergleichen
4 Commits
4b4609cd6c
...
990da710c1
| Autor | SHA1 | Datum | |
|---|---|---|---|
| 990da710c1 | |||
| b4ac8726b4 | |||
| 79da604226 | |||
| 0d207d2f0e |
Binäre Datei nicht angezeigt.
|
Nachher Breite: | Höhe: | Größe: 213 KiB |
+23
-3
@@ -619,7 +619,8 @@ function isGvlImportCandidate(value) {
|
|||||||
|
|
||||||
async function handleFetchOfficialGvlMessage() {
|
async function handleFetchOfficialGvlMessage() {
|
||||||
try {
|
try {
|
||||||
const { rawJson, responseStatus } = await fetchOfficialGvlJson();
|
const { rawJson, rawGvlSha256, responseStatus } =
|
||||||
|
await fetchOfficialGvlJson();
|
||||||
|
|
||||||
if (!isGvlImportCandidate(rawJson)) {
|
if (!isGvlImportCandidate(rawJson)) {
|
||||||
return {
|
return {
|
||||||
@@ -633,6 +634,7 @@ async function handleFetchOfficialGvlMessage() {
|
|||||||
const result = await VendorGetGvlService.ingestGvlSnapshot(db, rawJson, {
|
const result = await VendorGetGvlService.ingestGvlSnapshot(db, rawJson, {
|
||||||
sourceUrl: OFFICIAL_IAB_GVL_URL,
|
sourceUrl: OFFICIAL_IAB_GVL_URL,
|
||||||
fetchedAt: new Date().toISOString(),
|
fetchedAt: new Date().toISOString(),
|
||||||
|
rawGvlSha256: rawGvlSha256,
|
||||||
diagnostics: {
|
diagnostics: {
|
||||||
ingestionSource: "official_iab_fetch",
|
ingestionSource: "official_iab_fetch",
|
||||||
responseStatus: responseStatus
|
responseStatus: responseStatus
|
||||||
@@ -672,8 +674,24 @@ async function fetchOfficialGvlJson() {
|
|||||||
throw error;
|
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 {
|
return {
|
||||||
rawJson: await response.json(),
|
rawJson: JSON.parse(rawBody),
|
||||||
|
rawGvlSha256: rawGvlSha256,
|
||||||
responseStatus: response.status
|
responseStatus: response.status
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -758,7 +776,8 @@ async function runStartupGvlAutoUpdateCheck() {
|
|||||||
result: "started"
|
result: "started"
|
||||||
});
|
});
|
||||||
|
|
||||||
const { rawJson, responseStatus } = await fetchOfficialGvlJson();
|
const { rawJson, rawGvlSha256, responseStatus } =
|
||||||
|
await fetchOfficialGvlJson();
|
||||||
|
|
||||||
if (!isGvlImportCandidate(rawJson)) {
|
if (!isGvlImportCandidate(rawJson)) {
|
||||||
throw new Error("invalid_gvl_json");
|
throw new Error("invalid_gvl_json");
|
||||||
@@ -778,6 +797,7 @@ async function runStartupGvlAutoUpdateCheck() {
|
|||||||
{
|
{
|
||||||
sourceUrl: OFFICIAL_IAB_GVL_URL,
|
sourceUrl: OFFICIAL_IAB_GVL_URL,
|
||||||
fetchedAt: new Date().toISOString(),
|
fetchedAt: new Date().toISOString(),
|
||||||
|
rawGvlSha256: rawGvlSha256,
|
||||||
diagnostics: {
|
diagnostics: {
|
||||||
ingestionSource: "official_iab_auto_update",
|
ingestionSource: "official_iab_auto_update",
|
||||||
responseStatus: responseStatus,
|
responseStatus: responseStatus,
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const VENDORGET_DB_NAME = "vendorget_iv";
|
const VENDORGET_DB_NAME = "vendorget_iv";
|
||||||
const VENDORGET_DB_VERSION = 5;
|
const VENDORGET_DB_VERSION = 6;
|
||||||
|
|
||||||
const VENDORGET_STORE_NAMES = {
|
const VENDORGET_STORE_NAMES = {
|
||||||
consentStates: "consent_states",
|
consentStates: "consent_states",
|
||||||
consentEvents: "consent_events",
|
consentEvents: "consent_events",
|
||||||
observedRequests: "observed_requests",
|
observedRequests: "observed_requests",
|
||||||
|
gvlRawEvidence: "gvl_raw_evidence",
|
||||||
gvlSnapshots: "gvl_snapshots",
|
gvlSnapshots: "gvl_snapshots",
|
||||||
gvlSnapshotEvents: "gvl_snapshot_events",
|
gvlSnapshotEvents: "gvl_snapshot_events",
|
||||||
gvlVendors: "gvl_vendors",
|
gvlVendors: "gvl_vendors",
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ function openVendorGetDb() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
ensureGvlStores(db);
|
ensureGvlStores(db, event.target.transaction);
|
||||||
};
|
};
|
||||||
|
|
||||||
request.onsuccess = () => resolve(request.result);
|
request.onsuccess = () => resolve(request.result);
|
||||||
@@ -110,18 +110,73 @@ async function deleteVendorGetDatabase() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function ensureGvlStores(db) {
|
function ensureGvlStores(db, upgradeTransaction) {
|
||||||
|
if (!db.objectStoreNames.contains("gvl_raw_evidence")) {
|
||||||
|
const gvlRawEvidence = db.createObjectStore("gvl_raw_evidence", {
|
||||||
|
keyPath: "rawGvlSha256"
|
||||||
|
});
|
||||||
|
|
||||||
|
createIndexesIfMissing(gvlRawEvidence, [
|
||||||
|
"canonicalGvlSha256",
|
||||||
|
"vendorListVersion",
|
||||||
|
"fetchedAt",
|
||||||
|
"sourceUrl",
|
||||||
|
"ingestionSource",
|
||||||
|
"contentType",
|
||||||
|
"parseStatus"
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
const gvlRawEvidence = getUpgradeObjectStore(
|
||||||
|
db,
|
||||||
|
upgradeTransaction,
|
||||||
|
"gvl_raw_evidence"
|
||||||
|
);
|
||||||
|
|
||||||
|
if (gvlRawEvidence) {
|
||||||
|
createIndexesIfMissing(gvlRawEvidence, [
|
||||||
|
"canonicalGvlSha256",
|
||||||
|
"vendorListVersion",
|
||||||
|
"fetchedAt",
|
||||||
|
"sourceUrl",
|
||||||
|
"ingestionSource",
|
||||||
|
"contentType",
|
||||||
|
"parseStatus"
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
if (!db.objectStoreNames.contains("gvl_snapshots")) {
|
if (!db.objectStoreNames.contains("gvl_snapshots")) {
|
||||||
const gvlSnapshots = db.createObjectStore("gvl_snapshots", {
|
const gvlSnapshots = db.createObjectStore("gvl_snapshots", {
|
||||||
keyPath: "sha256"
|
keyPath: "sha256"
|
||||||
});
|
});
|
||||||
|
|
||||||
gvlSnapshots.createIndex("gvlRevision", "gvlRevision", { unique: false });
|
createIndexesIfMissing(gvlSnapshots, [
|
||||||
gvlSnapshots.createIndex("vendorListVersion", "vendorListVersion", {
|
"gvlRevision",
|
||||||
unique: false
|
"vendorListVersion",
|
||||||
});
|
"fetchedAt",
|
||||||
gvlSnapshots.createIndex("fetchedAt", "fetchedAt", { unique: false });
|
"sourceUrl",
|
||||||
gvlSnapshots.createIndex("sourceUrl", "sourceUrl", { unique: false });
|
"rawGvlSha256",
|
||||||
|
"canonicalGvlSha256",
|
||||||
|
"snapshotSha256"
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
const gvlSnapshots = getUpgradeObjectStore(
|
||||||
|
db,
|
||||||
|
upgradeTransaction,
|
||||||
|
"gvl_snapshots"
|
||||||
|
);
|
||||||
|
|
||||||
|
if (gvlSnapshots) {
|
||||||
|
createIndexesIfMissing(gvlSnapshots, [
|
||||||
|
"gvlRevision",
|
||||||
|
"vendorListVersion",
|
||||||
|
"fetchedAt",
|
||||||
|
"sourceUrl",
|
||||||
|
"rawGvlSha256",
|
||||||
|
"canonicalGvlSha256",
|
||||||
|
"snapshotSha256"
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!db.objectStoreNames.contains("gvl_snapshot_events")) {
|
if (!db.objectStoreNames.contains("gvl_snapshot_events")) {
|
||||||
@@ -130,22 +185,43 @@ function ensureGvlStores(db) {
|
|||||||
autoIncrement: true
|
autoIncrement: true
|
||||||
});
|
});
|
||||||
|
|
||||||
gvlSnapshotEvents.createIndex("eventType", "eventType", { unique: false });
|
createIndexesIfMissing(gvlSnapshotEvents, [
|
||||||
gvlSnapshotEvents.createIndex("capturedAt", "capturedAt", { unique: false });
|
"eventType",
|
||||||
gvlSnapshotEvents.createIndex("gvlRevision", "gvlRevision", {
|
"capturedAt",
|
||||||
unique: false
|
"gvlRevision",
|
||||||
});
|
"vendorListVersion",
|
||||||
gvlSnapshotEvents.createIndex("vendorListVersion", "vendorListVersion", {
|
"sha256",
|
||||||
unique: false
|
"sourceUrl",
|
||||||
});
|
"rawGvlSha256",
|
||||||
gvlSnapshotEvents.createIndex("sha256", "sha256", { unique: false });
|
"canonicalGvlSha256",
|
||||||
gvlSnapshotEvents.createIndex("sourceUrl", "sourceUrl", { unique: false });
|
"snapshotSha256"
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
ensureGvlRelationshipStores(db);
|
const gvlSnapshotEvents = getUpgradeObjectStore(
|
||||||
|
db,
|
||||||
|
upgradeTransaction,
|
||||||
|
"gvl_snapshot_events"
|
||||||
|
);
|
||||||
|
|
||||||
|
if (gvlSnapshotEvents) {
|
||||||
|
createIndexesIfMissing(gvlSnapshotEvents, [
|
||||||
|
"eventType",
|
||||||
|
"capturedAt",
|
||||||
|
"gvlRevision",
|
||||||
|
"vendorListVersion",
|
||||||
|
"sha256",
|
||||||
|
"sourceUrl",
|
||||||
|
"rawGvlSha256",
|
||||||
|
"canonicalGvlSha256",
|
||||||
|
"snapshotSha256"
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
ensureGvlRelationshipStores(db, upgradeTransaction);
|
||||||
}
|
}
|
||||||
|
|
||||||
function ensureGvlRelationshipStores(db) {
|
function ensureGvlRelationshipStores(db, upgradeTransaction) {
|
||||||
const gvlRelationshipStoreDefinitions = [
|
const gvlRelationshipStoreDefinitions = [
|
||||||
{
|
{
|
||||||
name: "gvl_vendors",
|
name: "gvl_vendors",
|
||||||
@@ -154,28 +230,66 @@ function ensureGvlRelationshipStores(db) {
|
|||||||
"vendorId",
|
"vendorId",
|
||||||
"name",
|
"name",
|
||||||
"policyUrl",
|
"policyUrl",
|
||||||
"deletedDate"
|
"deletedDate",
|
||||||
|
"rawGvlSha256",
|
||||||
|
"canonicalGvlSha256",
|
||||||
|
"snapshotSha256"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "gvl_purposes",
|
name: "gvl_purposes",
|
||||||
indexes: ["vendorListVersion", "purposeId", "name"]
|
indexes: [
|
||||||
|
"vendorListVersion",
|
||||||
|
"purposeId",
|
||||||
|
"name",
|
||||||
|
"rawGvlSha256",
|
||||||
|
"canonicalGvlSha256",
|
||||||
|
"snapshotSha256"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "gvl_special_purposes",
|
name: "gvl_special_purposes",
|
||||||
indexes: ["vendorListVersion", "specialPurposeId", "name"]
|
indexes: [
|
||||||
|
"vendorListVersion",
|
||||||
|
"specialPurposeId",
|
||||||
|
"name",
|
||||||
|
"rawGvlSha256",
|
||||||
|
"canonicalGvlSha256",
|
||||||
|
"snapshotSha256"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "gvl_features",
|
name: "gvl_features",
|
||||||
indexes: ["vendorListVersion", "featureId", "name"]
|
indexes: [
|
||||||
|
"vendorListVersion",
|
||||||
|
"featureId",
|
||||||
|
"name",
|
||||||
|
"rawGvlSha256",
|
||||||
|
"canonicalGvlSha256",
|
||||||
|
"snapshotSha256"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "gvl_special_features",
|
name: "gvl_special_features",
|
||||||
indexes: ["vendorListVersion", "specialFeatureId", "name"]
|
indexes: [
|
||||||
|
"vendorListVersion",
|
||||||
|
"specialFeatureId",
|
||||||
|
"name",
|
||||||
|
"rawGvlSha256",
|
||||||
|
"canonicalGvlSha256",
|
||||||
|
"snapshotSha256"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "gvl_data_categories",
|
name: "gvl_data_categories",
|
||||||
indexes: ["vendorListVersion", "dataCategoryId", "name"]
|
indexes: [
|
||||||
|
"vendorListVersion",
|
||||||
|
"dataCategoryId",
|
||||||
|
"name",
|
||||||
|
"rawGvlSha256",
|
||||||
|
"canonicalGvlSha256",
|
||||||
|
"snapshotSha256"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "gvl_vendor_relationships",
|
name: "gvl_vendor_relationships",
|
||||||
@@ -183,13 +297,26 @@ function ensureGvlRelationshipStores(db) {
|
|||||||
"vendorListVersion",
|
"vendorListVersion",
|
||||||
"vendorId",
|
"vendorId",
|
||||||
"relationshipType",
|
"relationshipType",
|
||||||
"relatedId"
|
"relatedId",
|
||||||
|
"rawGvlSha256",
|
||||||
|
"canonicalGvlSha256",
|
||||||
|
"snapshotSha256"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
gvlRelationshipStoreDefinitions.forEach((storeDefinition) => {
|
gvlRelationshipStoreDefinitions.forEach((storeDefinition) => {
|
||||||
if (db.objectStoreNames.contains(storeDefinition.name)) {
|
if (db.objectStoreNames.contains(storeDefinition.name)) {
|
||||||
|
const objectStore = getUpgradeObjectStore(
|
||||||
|
db,
|
||||||
|
upgradeTransaction,
|
||||||
|
storeDefinition.name
|
||||||
|
);
|
||||||
|
|
||||||
|
if (objectStore) {
|
||||||
|
createIndexesIfMissing(objectStore, storeDefinition.indexes);
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -197,8 +324,24 @@ function ensureGvlRelationshipStores(db) {
|
|||||||
keyPath: "id"
|
keyPath: "id"
|
||||||
});
|
});
|
||||||
|
|
||||||
storeDefinition.indexes.forEach((indexName) => {
|
createIndexesIfMissing(objectStore, storeDefinition.indexes);
|
||||||
objectStore.createIndex(indexName, indexName, { unique: false });
|
});
|
||||||
});
|
}
|
||||||
|
|
||||||
|
function getUpgradeObjectStore(db, upgradeTransaction, storeName) {
|
||||||
|
if (!upgradeTransaction || !db.objectStoreNames.contains(storeName)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return upgradeTransaction.objectStore(storeName);
|
||||||
|
}
|
||||||
|
|
||||||
|
function createIndexesIfMissing(objectStore, indexNames) {
|
||||||
|
indexNames.forEach((indexName) => {
|
||||||
|
if (objectStore.indexNames.contains(indexName)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
objectStore.createIndex(indexName, indexName, { unique: false });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,11 +9,58 @@ async function calculateGvlSnapshotSha256(rawJson) {
|
|||||||
.join("");
|
.join("");
|
||||||
}
|
}
|
||||||
|
|
||||||
async function buildGvlSnapshotRecord(rawJson, sourceUrl, fetchedAt) {
|
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,
|
||||||
|
rawGvlSha256
|
||||||
|
) {
|
||||||
const gvlJson = normalizeGvlSnapshotValueForMetadata(rawJson);
|
const gvlJson = normalizeGvlSnapshotValueForMetadata(rawJson);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
sha256: await calculateGvlSnapshotSha256(rawJson),
|
sha256: await calculateGvlSnapshotSha256(rawJson),
|
||||||
|
rawGvlSha256: rawGvlSha256 ?? null,
|
||||||
vendorListVersion: gvlJson?.vendorListVersion ?? null,
|
vendorListVersion: gvlJson?.vendorListVersion ?? null,
|
||||||
gvlSpecificationVersion: gvlJson?.gvlSpecificationVersion ?? null,
|
gvlSpecificationVersion: gvlJson?.gvlSpecificationVersion ?? null,
|
||||||
tcfPolicyVersion: gvlJson?.tcfPolicyVersion ?? null,
|
tcfPolicyVersion: gvlJson?.tcfPolicyVersion ?? null,
|
||||||
@@ -88,7 +135,8 @@ async function ingestGvlSnapshot(db, rawJson, options = {}) {
|
|||||||
const snapshot = await buildGvlSnapshotRecord(
|
const snapshot = await buildGvlSnapshotRecord(
|
||||||
rawJson,
|
rawJson,
|
||||||
options.sourceUrl ?? null,
|
options.sourceUrl ?? null,
|
||||||
options.fetchedAt ?? null
|
options.fetchedAt ?? null,
|
||||||
|
options.rawGvlSha256 ?? null
|
||||||
);
|
);
|
||||||
const storeResult = await storeGvlSnapshotIfNew(db, snapshot);
|
const storeResult = await storeGvlSnapshotIfNew(db, snapshot);
|
||||||
const alreadyKnown = !storeResult.stored;
|
const alreadyKnown = !storeResult.stored;
|
||||||
@@ -149,6 +197,8 @@ function countObjectEntries(value) {
|
|||||||
|
|
||||||
globalThis.VendorGetGvlService = {
|
globalThis.VendorGetGvlService = {
|
||||||
calculateGvlSnapshotSha256,
|
calculateGvlSnapshotSha256,
|
||||||
|
calculateRawGvlSha256,
|
||||||
|
storeGvlRawEvidenceIfNew,
|
||||||
buildGvlSnapshotRecord,
|
buildGvlSnapshotRecord,
|
||||||
storeGvlSnapshotIfNew,
|
storeGvlSnapshotIfNew,
|
||||||
recordGvlSnapshotEvent,
|
recordGvlSnapshotEvent,
|
||||||
|
|||||||
@@ -175,3 +175,45 @@ button:disabled {
|
|||||||
cursor: default;
|
cursor: default;
|
||||||
opacity: 0.65;
|
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">
|
<button id="evidence-export-json-button" type="button">
|
||||||
Export Evidence JSON
|
Export Evidence JSON
|
||||||
</button>
|
</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-export-json-status" class="retention-status" aria-live="polite"></div>
|
||||||
<div id="evidence-retention-status" class="retention-status" aria-live="polite">
|
<div id="evidence-retention-status" class="retention-status" aria-live="polite">
|
||||||
Status wird geladen
|
Status wird geladen
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</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>
|
</main>
|
||||||
|
|
||||||
<script src="../core/settings-storage.js"></script>
|
<script src="../core/settings-storage.js"></script>
|
||||||
|
|||||||
@@ -16,6 +16,18 @@ const evidenceDashboardButton = document.getElementById(
|
|||||||
const evidenceExportJsonButton = document.getElementById(
|
const evidenceExportJsonButton = document.getElementById(
|
||||||
"evidence-export-json-button"
|
"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(
|
const evidenceExportJsonStatus = document.getElementById(
|
||||||
"evidence-export-json-status"
|
"evidence-export-json-status"
|
||||||
);
|
);
|
||||||
@@ -69,6 +81,9 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
evidenceExportJsonButton.addEventListener("click", exportEvidenceJsonFile);
|
evidenceExportJsonButton.addEventListener("click", exportEvidenceJsonFile);
|
||||||
|
evidencePurgeUnlockedButton.addEventListener("click", openPurgeConfirmModal);
|
||||||
|
evidencePurgeCancelButton.addEventListener("click", closePurgeConfirmModal);
|
||||||
|
evidencePurgeConfirmButton.addEventListener("click", purgeUnlockedEvidence);
|
||||||
});
|
});
|
||||||
|
|
||||||
async function renderSettings() {
|
async function renderSettings() {
|
||||||
@@ -143,6 +158,48 @@ function renderEvidenceRetentionMessage(message) {
|
|||||||
evidenceRetentionStatus.textContent = 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() {
|
async function exportEvidenceJsonFile() {
|
||||||
evidenceExportJsonButton.disabled = true;
|
evidenceExportJsonButton.disabled = true;
|
||||||
renderEvidenceExportJsonMessage("Export läuft…");
|
renderEvidenceExportJsonMessage("Export läuft…");
|
||||||
|
|||||||
In neuem Issue referenzieren
Einen Benutzer sperren