Dateien
VG-Environment/src/background/db/db-retention.js
T

219 Zeilen
5.9 KiB
JavaScript

"use strict";
function countEvidenceRecords(db) {
return countRecordsInStores(db, VENDORGET_EVIDENCE_STORE_NAMES);
}
function countLockedEvidenceRecords(db) {
return countRecordsMatching(db, VENDORGET_EVIDENCE_STORE_NAMES, (record) => {
return record?.bolRecordLock === true;
});
}
function getEvidenceStoreCounts(db) {
return new Promise((resolve, reject) => {
const storeCounts = {};
const tx = db.transaction(VENDORGET_EVIDENCE_STORE_NAMES, "readonly");
tx.onerror = () => reject(tx.error);
tx.onabort = () => reject(tx.error);
tx.oncomplete = () => resolve(storeCounts);
for (const storeName of VENDORGET_EVIDENCE_STORE_NAMES) {
const countRequest = tx.objectStore(storeName).count();
countRequest.onsuccess = () => {
storeCounts[storeName] = countRequest.result;
};
}
});
}
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);
tx.onabort = () => reject(tx.error);
tx.oncomplete = () => {
resolve({
success: true,
deletedCount,
keptLockedCount,
keptGvlWorkspaceProtectedCount,
gvlWorkspaceProtectionNotice:
keptGvlWorkspaceProtectedCount > 0
? "Diese GVL-Evidence wurde noch nicht in den Vault exportiert."
: null
});
};
for (const storeName of VENDORGET_EVIDENCE_STORE_NAMES) {
const cursorRequest = tx.objectStore(storeName).openCursor();
cursorRequest.onsuccess = () => {
const cursor = cursorRequest.result;
if (!cursor) {
return;
}
if (cursor.value?.bolRecordLock === true) {
keptLockedCount += 1;
cursor.continue();
return;
}
if (
isGvlWorkspaceProtectedRecord(
storeName,
cursor.value,
gvlWorkspaceProtection
)
) {
keptGvlWorkspaceProtectedCount += 1;
cursor.continue();
return;
}
deletedCount += 1;
cursor.delete();
cursor.continue();
};
}
});
}
// TODO: GVL-Datenpflege darf nicht storeweise per clear() erfolgen.
// Loeschbar ist nur eine GVL-Revision, wenn ihre zugehoerigen Raw-, Snapshot-,
// Event- und normalisierten Records identifiziert sind, ihr Schutzstatus
// vollstaendig bewertet wurde und eine vorhandene Vault-/Workspace-Schutzlogik
// die Loeschung erlaubt.
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;
const tx = db.transaction(storeNames, "readonly");
tx.onerror = () => reject(tx.error);
tx.onabort = () => reject(tx.error);
tx.oncomplete = () => resolve(totalCount);
for (const storeName of storeNames) {
const countRequest = tx.objectStore(storeName).count();
countRequest.onsuccess = () => {
totalCount += countRequest.result;
};
}
});
}
function countRecordsMatching(db, storeNames, predicate) {
return new Promise((resolve, reject) => {
let totalCount = 0;
const tx = db.transaction(storeNames, "readonly");
tx.onerror = () => reject(tx.error);
tx.onabort = () => reject(tx.error);
tx.oncomplete = () => resolve(totalCount);
for (const storeName of storeNames) {
const cursorRequest = tx.objectStore(storeName).openCursor();
cursorRequest.onsuccess = () => {
const cursor = cursorRequest.result;
if (!cursor) {
return;
}
if (predicate(cursor.value)) {
totalCount += 1;
}
cursor.continue();
};
}
});
}