219 Zeilen
5.9 KiB
JavaScript
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();
|
|
};
|
|
}
|
|
});
|
|
}
|