Add verified GVL evidence import provenance and protection

Dieser Commit ist enthalten in:
2026-06-10 19:17:31 +02:00
Ursprung eb70f0ce81
Commit a3ca8019a1
8 geänderte Dateien mit 891 neuen und 34 gelöschten Zeilen
+96 -2
Datei anzeigen
@@ -29,10 +29,13 @@ function getEvidenceStoreCounts(db) {
});
}
function purgeUnlockedEvidenceRecords(db) {
async function purgeUnlockedEvidenceRecords(db) {
const gvlWorkspaceProtection = await buildGvlWorkspaceProtectionIndex(db);
return new Promise((resolve, reject) => {
let deletedCount = 0;
let keptLockedCount = 0;
let keptGvlWorkspaceProtectedCount = 0;
const tx = db.transaction(VENDORGET_EVIDENCE_STORE_NAMES, "readwrite");
tx.onerror = () => reject(tx.error);
@@ -41,7 +44,12 @@ function purgeUnlockedEvidenceRecords(db) {
resolve({
success: true,
deletedCount,
keptLockedCount
keptLockedCount,
keptGvlWorkspaceProtectedCount,
gvlWorkspaceProtectionNotice:
keptGvlWorkspaceProtectedCount > 0
? "Diese GVL-Evidence wurde noch nicht in den Vault exportiert."
: null
});
};
@@ -61,6 +69,18 @@ function purgeUnlockedEvidenceRecords(db) {
return;
}
if (
isGvlWorkspaceProtectedRecord(
storeName,
cursor.value,
gvlWorkspaceProtection
)
) {
keptGvlWorkspaceProtectedCount += 1;
cursor.continue();
return;
}
deletedCount += 1;
cursor.delete();
cursor.continue();
@@ -69,6 +89,80 @@ function purgeUnlockedEvidenceRecords(db) {
});
}
function buildGvlWorkspaceProtectionIndex(db) {
return new Promise((resolve, reject) => {
const protectedSnapshotSha256 = new Set();
const protectedRawGvlSha256 = new Set();
const tx = db.transaction([VENDORGET_STORE_NAMES.gvlSnapshots], "readonly");
const cursorRequest = tx
.objectStore(VENDORGET_STORE_NAMES.gvlSnapshots)
.openCursor();
cursorRequest.onerror = () => reject(cursorRequest.error);
cursorRequest.onsuccess = () => {
const cursor = cursorRequest.result;
if (!cursor) {
return;
}
const snapshot = cursor.value;
const provenanceState = getGvlEvidenceProvenanceState(snapshot);
if (provenanceState.workspaceDeleteProtected) {
if (snapshot.sha256) {
protectedSnapshotSha256.add(snapshot.sha256);
}
if (snapshot.rawGvlSha256) {
protectedRawGvlSha256.add(snapshot.rawGvlSha256);
}
}
cursor.continue();
};
tx.onerror = () => reject(tx.error);
tx.onabort = () => reject(tx.error);
tx.oncomplete = () => {
resolve({
protectedSnapshotSha256,
protectedRawGvlSha256
});
};
});
}
function isGvlWorkspaceProtectedRecord(storeName, record, protectionIndex) {
if (!record || typeof record !== "object") {
return false;
}
if (storeName === VENDORGET_STORE_NAMES.gvlSnapshots) {
return protectionIndex.protectedSnapshotSha256.has(record.sha256);
}
if (storeName === VENDORGET_STORE_NAMES.gvlRawEvidence) {
return protectionIndex.protectedRawGvlSha256.has(record.rawGvlSha256);
}
if (
[
VENDORGET_STORE_NAMES.gvlVendors,
VENDORGET_STORE_NAMES.gvlPurposes,
VENDORGET_STORE_NAMES.gvlSpecialPurposes,
VENDORGET_STORE_NAMES.gvlFeatures,
VENDORGET_STORE_NAMES.gvlSpecialFeatures,
VENDORGET_STORE_NAMES.gvlDataCategories,
VENDORGET_STORE_NAMES.gvlVendorRelationships
].includes(storeName)
) {
return protectionIndex.protectedSnapshotSha256.has(record.snapshotSha256);
}
return false;
}
function countRecordsInStores(db, storeNames) {
return new Promise((resolve, reject) => {
let totalCount = 0;