Commits vergleichen
1 Commits
1f10389016
..
master
| Autor | SHA1 | Datum | |
|---|---|---|---|
| 904787c115 |
@@ -40,6 +40,7 @@
|
|||||||
"src/background/gvl-service.js",
|
"src/background/gvl-service.js",
|
||||||
"src/core/binary-utils.js",
|
"src/core/binary-utils.js",
|
||||||
"src/core/tcf-core-metadata-decoder.js",
|
"src/core/tcf-core-metadata-decoder.js",
|
||||||
|
"src/core/consent-diff.js",
|
||||||
"src/background.js"
|
"src/background.js"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|||||||
+71
-6
@@ -224,6 +224,7 @@ async function handleVendorGetMessage(message, sender) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const latestPingData = tabId !== null ? getLatestTcfPing(tabId) : null;
|
const latestPingData = tabId !== null ? getLatestTcfPing(tabId) : null;
|
||||||
|
const activeConsentCaptureSession = getActiveConsentCaptureSession(sender);
|
||||||
|
|
||||||
const consentState = buildConsentStateV1(
|
const consentState = buildConsentStateV1(
|
||||||
message.payload.payload,
|
message.payload.payload,
|
||||||
@@ -235,7 +236,7 @@ async function handleVendorGetMessage(message, sender) {
|
|||||||
stableStringify(consentState.fingerprintSource)
|
stableStringify(consentState.fingerprintSource)
|
||||||
);
|
);
|
||||||
|
|
||||||
const captureSessionId = getActiveConsentCaptureSessionId(sender);
|
const captureSessionId = activeConsentCaptureSession?.captureSessionId ?? null;
|
||||||
|
|
||||||
rememberLatestConsentState(consentState);
|
rememberLatestConsentState(consentState);
|
||||||
|
|
||||||
@@ -245,12 +246,19 @@ async function handleVendorGetMessage(message, sender) {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (captureSessionId) {
|
if (captureSessionId) {
|
||||||
await persistConsentExecutionEvent({
|
const consentExecutionEvent = await persistConsentExecutionEvent({
|
||||||
captureSessionId,
|
captureSessionId,
|
||||||
consentState,
|
consentState,
|
||||||
rawCapture: message.payload.payload,
|
rawCapture: message.payload.payload,
|
||||||
sender
|
sender
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await persistConsentDiffEvent({
|
||||||
|
captureSessionId,
|
||||||
|
providerAnnouncementEvent:
|
||||||
|
activeConsentCaptureSession?.providerAnnouncementEvents?.[0] ?? null,
|
||||||
|
consentExecutionEvent
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
completeConsentCaptureSession(sender);
|
completeConsentCaptureSession(sender);
|
||||||
@@ -1044,17 +1052,20 @@ async function handleStartPreConsentCaptureMessage(message) {
|
|||||||
|
|
||||||
session.status = "recording";
|
session.status = "recording";
|
||||||
session.captureSessionId = createCaptureSessionId();
|
session.captureSessionId = createCaptureSessionId();
|
||||||
|
session.providerAnnouncementEvents = [];
|
||||||
updateConsentCaptureBadge(session);
|
updateConsentCaptureBadge(session);
|
||||||
|
|
||||||
const bufferedEvents = session.bufferedPreConsentEvents;
|
const bufferedEvents = session.bufferedPreConsentEvents;
|
||||||
session.bufferedPreConsentEvents = [];
|
session.bufferedPreConsentEvents = [];
|
||||||
|
|
||||||
for (const bufferedEvent of bufferedEvents) {
|
for (const bufferedEvent of bufferedEvents) {
|
||||||
await persistProviderAnnouncementEvent({
|
const providerAnnouncementEvent = await persistProviderAnnouncementEvent({
|
||||||
captureSessionId: session.captureSessionId,
|
captureSessionId: session.captureSessionId,
|
||||||
rawCapture: bufferedEvent.rawCapture,
|
rawCapture: bufferedEvent.rawCapture,
|
||||||
sender: bufferedEvent.sender
|
sender: bufferedEvent.sender
|
||||||
});
|
});
|
||||||
|
|
||||||
|
session.providerAnnouncementEvents.push(providerAnnouncementEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -2393,6 +2404,7 @@ function startAttentionConsentCaptureSession(rawCapture, sender) {
|
|||||||
status: "attention",
|
status: "attention",
|
||||||
captureSessionId: null,
|
captureSessionId: null,
|
||||||
bufferedPreConsentEvents: [],
|
bufferedPreConsentEvents: [],
|
||||||
|
providerAnnouncementEvents: [],
|
||||||
timeoutId: null,
|
timeoutId: null,
|
||||||
page: buildConsentEventPageContext(rawCapture, sender),
|
page: buildConsentEventPageContext(rawCapture, sender),
|
||||||
detectedAt: new Date().toISOString(),
|
detectedAt: new Date().toISOString(),
|
||||||
@@ -2440,11 +2452,14 @@ async function handlePreConsentTcfEvent(rawCapture, sender) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (session?.status === "recording") {
|
if (session?.status === "recording") {
|
||||||
await persistProviderAnnouncementEvent({
|
const providerAnnouncementEvent = await persistProviderAnnouncementEvent({
|
||||||
captureSessionId: session.captureSessionId,
|
captureSessionId: session.captureSessionId,
|
||||||
rawCapture,
|
rawCapture,
|
||||||
sender
|
sender
|
||||||
});
|
});
|
||||||
|
session.providerAnnouncementEvents =
|
||||||
|
session.providerAnnouncementEvents ?? [];
|
||||||
|
session.providerAnnouncementEvents.push(providerAnnouncementEvent);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2452,6 +2467,12 @@ async function handlePreConsentTcfEvent(rawCapture, sender) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getActiveConsentCaptureSessionId(sender) {
|
function getActiveConsentCaptureSessionId(sender) {
|
||||||
|
const session = getActiveConsentCaptureSession(sender);
|
||||||
|
|
||||||
|
return session?.captureSessionId ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getActiveConsentCaptureSession(sender) {
|
||||||
const sessionKey = getConsentCaptureSessionKey(sender);
|
const sessionKey = getConsentCaptureSessionKey(sender);
|
||||||
const session = sessionKey ? consentCaptureSessions.get(sessionKey) : null;
|
const session = sessionKey ? consentCaptureSessions.get(sessionKey) : null;
|
||||||
|
|
||||||
@@ -2459,7 +2480,7 @@ function getActiveConsentCaptureSessionId(sender) {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return session.captureSessionId ?? null;
|
return session;
|
||||||
}
|
}
|
||||||
|
|
||||||
function hasCompletedConsentCaptureSessionForTab(tabId) {
|
function hasCompletedConsentCaptureSessionForTab(tabId) {
|
||||||
@@ -2492,6 +2513,7 @@ function completeConsentCaptureSession(sender) {
|
|||||||
status: "completed",
|
status: "completed",
|
||||||
captureSessionId: null,
|
captureSessionId: null,
|
||||||
bufferedPreConsentEvents: [],
|
bufferedPreConsentEvents: [],
|
||||||
|
providerAnnouncementEvents: [],
|
||||||
timeoutId: null
|
timeoutId: null
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -3094,16 +3116,59 @@ async function persistConsentExecutionEvent({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function persistConsentDiffEvent({
|
||||||
|
captureSessionId,
|
||||||
|
providerAnnouncementEvent,
|
||||||
|
consentExecutionEvent
|
||||||
|
}) {
|
||||||
|
const db = await openVendorGetDb();
|
||||||
|
const now = new Date().toISOString();
|
||||||
|
const consentDiff = buildConsentDiff({
|
||||||
|
captureSessionId,
|
||||||
|
providerAnnouncement: providerAnnouncementEvent,
|
||||||
|
consentExecution: consentExecutionEvent,
|
||||||
|
derivedAt: now
|
||||||
|
});
|
||||||
|
|
||||||
|
return addConsentEventRecord(db, {
|
||||||
|
eventType: "consent_diff",
|
||||||
|
capturedAt: now,
|
||||||
|
recordedAt: now,
|
||||||
|
recordingSource: EVIDENCE_RECORDING_SOURCE,
|
||||||
|
captureSessionId,
|
||||||
|
stateFingerprint: consentExecutionEvent?.stateFingerprint ?? null,
|
||||||
|
page: consentExecutionEvent?.page ?? null,
|
||||||
|
rawEventName: "consent_diff",
|
||||||
|
ruleId: CONSENT_DIFF_RULE_ID,
|
||||||
|
ruleVersion: CONSENT_DIFF_RULE_VERSION,
|
||||||
|
consentDiff,
|
||||||
|
diagnostics: {
|
||||||
|
consentEvidenceRole: "consentDiff",
|
||||||
|
ruleId: CONSENT_DIFF_RULE_ID,
|
||||||
|
ruleVersion: CONSENT_DIFF_RULE_VERSION,
|
||||||
|
sourceProviderAnnouncementId: providerAnnouncementEvent?.id ?? null,
|
||||||
|
sourceConsentExecutionId: consentExecutionEvent?.id ?? null
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function addConsentEventRecord(db, record) {
|
function addConsentEventRecord(db, record) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const tx = db.transaction(["consent_events"], "readwrite");
|
const tx = db.transaction(["consent_events"], "readwrite");
|
||||||
const eventsStore = tx.objectStore("consent_events");
|
const eventsStore = tx.objectStore("consent_events");
|
||||||
const request = eventsStore.add(record);
|
const request = eventsStore.add(record);
|
||||||
|
let storedRecord = record;
|
||||||
|
|
||||||
request.onerror = () => reject(request.error);
|
request.onerror = () => reject(request.error);
|
||||||
|
request.onsuccess = () => {
|
||||||
|
storedRecord = {
|
||||||
|
...record,
|
||||||
|
id: request.result
|
||||||
|
};
|
||||||
|
};
|
||||||
tx.onerror = () => reject(tx.error);
|
tx.onerror = () => reject(tx.error);
|
||||||
tx.onabort = () => reject(tx.error);
|
tx.onabort = () => reject(tx.error);
|
||||||
tx.oncomplete = () => resolve(record);
|
tx.oncomplete = () => resolve(storedRecord);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ body {
|
|||||||
h1,
|
h1,
|
||||||
h2,
|
h2,
|
||||||
h3,
|
h3,
|
||||||
|
h4,
|
||||||
p {
|
p {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
@@ -49,6 +50,11 @@ h3 {
|
|||||||
color: #cbd5e1;
|
color: #cbd5e1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
h4 {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #cbd5e1;
|
||||||
|
}
|
||||||
|
|
||||||
p {
|
p {
|
||||||
max-width: 760px;
|
max-width: 760px;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
@@ -139,6 +145,165 @@ th {
|
|||||||
margin-top: 18px;
|
margin-top: 18px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.finding-overview {
|
||||||
|
display: grid;
|
||||||
|
gap: 10px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.finding-note {
|
||||||
|
max-width: 900px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.finding-list {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||||
|
gap: 1px;
|
||||||
|
margin: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
border: 1px solid #334155;
|
||||||
|
border-radius: 4px;
|
||||||
|
background: #334155;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.finding-list div {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: minmax(160px, 220px) 1fr;
|
||||||
|
gap: 10px;
|
||||||
|
min-width: 0;
|
||||||
|
padding: 10px 12px;
|
||||||
|
background: #1f2937;
|
||||||
|
}
|
||||||
|
|
||||||
|
.finding-list dt {
|
||||||
|
color: #cbd5e1;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
.finding-list dd {
|
||||||
|
margin: 0;
|
||||||
|
overflow-wrap: anywhere;
|
||||||
|
color: #e5edf5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.consent-diff {
|
||||||
|
display: grid;
|
||||||
|
gap: 10px;
|
||||||
|
margin-top: 10px;
|
||||||
|
padding: 10px;
|
||||||
|
border: 1px solid #334155;
|
||||||
|
border-radius: 4px;
|
||||||
|
background: #172033;
|
||||||
|
}
|
||||||
|
|
||||||
|
.compact-definition-list {
|
||||||
|
display: grid;
|
||||||
|
gap: 6px;
|
||||||
|
margin: 0;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.compact-definition-list div {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: minmax(150px, 220px) 1fr;
|
||||||
|
gap: 10px;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.compact-definition-list dt {
|
||||||
|
color: #cbd5e1;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
.compact-definition-list dd {
|
||||||
|
margin: 0;
|
||||||
|
overflow-wrap: anywhere;
|
||||||
|
}
|
||||||
|
|
||||||
|
.diff-note {
|
||||||
|
max-width: none;
|
||||||
|
font-size: 12px;
|
||||||
|
color: #cbd5e1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.consent-diff-primary {
|
||||||
|
display: grid;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.consent-diff-findings {
|
||||||
|
display: grid;
|
||||||
|
gap: 6px;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.consent-diff-findings li {
|
||||||
|
padding: 9px 10px;
|
||||||
|
border: 1px solid #334155;
|
||||||
|
border-radius: 4px;
|
||||||
|
color: #e5edf5;
|
||||||
|
background: #1f2937;
|
||||||
|
overflow-wrap: anywhere;
|
||||||
|
}
|
||||||
|
|
||||||
|
.consent-diff-finding-details summary {
|
||||||
|
cursor: pointer;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
.consent-diff-finding-body {
|
||||||
|
display: grid;
|
||||||
|
gap: 8px;
|
||||||
|
margin-top: 10px;
|
||||||
|
padding-top: 10px;
|
||||||
|
border-top: 1px solid #334155;
|
||||||
|
}
|
||||||
|
|
||||||
|
.consent-change-categories,
|
||||||
|
.consent-change-category-body {
|
||||||
|
display: grid;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.consent-change-category {
|
||||||
|
padding: 8px 10px;
|
||||||
|
border: 1px solid #334155;
|
||||||
|
border-radius: 4px;
|
||||||
|
background: #172033;
|
||||||
|
}
|
||||||
|
|
||||||
|
.consent-change-category summary,
|
||||||
|
.consent-change-collapsed-list summary {
|
||||||
|
cursor: pointer;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
.consent-change-list-block {
|
||||||
|
display: grid;
|
||||||
|
gap: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.inline-id-list {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 6px;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.inline-id-list li {
|
||||||
|
padding: 3px 6px;
|
||||||
|
border: 1px solid #334155;
|
||||||
|
border-radius: 3px;
|
||||||
|
background: #0f172a;
|
||||||
|
font-size: 12px;
|
||||||
|
color: #e5edf5;
|
||||||
|
}
|
||||||
|
|
||||||
.inspector-table th,
|
.inspector-table th,
|
||||||
.inspector-table td {
|
.inspector-table td {
|
||||||
vertical-align: top;
|
vertical-align: top;
|
||||||
@@ -227,4 +392,12 @@ th {
|
|||||||
.inspector-table .inspector-explanation {
|
.inspector-table .inspector-explanation {
|
||||||
width: auto;
|
width: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.finding-list {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
.finding-list div {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,6 +47,7 @@
|
|||||||
<section class="consent-detail" aria-labelledby="consent-detail-title">
|
<section class="consent-detail" aria-labelledby="consent-detail-title">
|
||||||
<h2 id="consent-detail-title">Ausgewählter Consent-Zustand</h2>
|
<h2 id="consent-detail-title">Ausgewählter Consent-Zustand</h2>
|
||||||
<div id="consent-detail-observation"></div>
|
<div id="consent-detail-observation"></div>
|
||||||
|
<div id="consent-detail-diff"></div>
|
||||||
<div id="consent-detail-basics"></div>
|
<div id="consent-detail-basics"></div>
|
||||||
<div id="consent-detail-summary"></div>
|
<div id="consent-detail-summary"></div>
|
||||||
<div id="consent-detail-publisher"></div>
|
<div id="consent-detail-publisher"></div>
|
||||||
|
|||||||
Datei-Diff unterdrückt, da er zu groß ist
Diff laden
@@ -0,0 +1,374 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
var CONSENT_DIFF_RULE_ID = "consent_diff";
|
||||||
|
var CONSENT_DIFF_RULE_VERSION = 1;
|
||||||
|
|
||||||
|
const CONSENT_DIFF_SCALAR_AXES = [
|
||||||
|
"tcString",
|
||||||
|
"addtlConsent",
|
||||||
|
"vendorListVersion",
|
||||||
|
"cmpId",
|
||||||
|
"cmpVersion",
|
||||||
|
"tcfPolicyVersion",
|
||||||
|
"gdprApplies",
|
||||||
|
"cmpStatus"
|
||||||
|
];
|
||||||
|
|
||||||
|
const CONSENT_DIFF_OBJECT_AXES = [
|
||||||
|
"purpose.consents",
|
||||||
|
"vendor.consents",
|
||||||
|
"specialFeatureOptins"
|
||||||
|
];
|
||||||
|
|
||||||
|
function buildConsentDiff({
|
||||||
|
captureSessionId,
|
||||||
|
providerAnnouncement,
|
||||||
|
consentExecution,
|
||||||
|
derivedAt
|
||||||
|
}) {
|
||||||
|
const providerRaw = cloneConsentDiffValue(
|
||||||
|
providerAnnouncement?.rawTcData ?? null
|
||||||
|
);
|
||||||
|
const executionRaw = cloneConsentDiffValue(consentExecution?.rawTcData ?? null);
|
||||||
|
const providerWork = buildConsentDiffWorkCopy(
|
||||||
|
providerAnnouncement,
|
||||||
|
providerRaw
|
||||||
|
);
|
||||||
|
const executionWork = buildConsentDiffWorkCopy(consentExecution, executionRaw);
|
||||||
|
const axes = {};
|
||||||
|
|
||||||
|
CONSENT_DIFF_SCALAR_AXES.forEach((axis) => {
|
||||||
|
axes[axis] = compareConsentDiffScalarAxis(
|
||||||
|
axis,
|
||||||
|
providerWork,
|
||||||
|
executionWork
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
CONSENT_DIFF_OBJECT_AXES.forEach((axis) => {
|
||||||
|
axes[axis] = compareConsentDiffObjectAxis(
|
||||||
|
axis,
|
||||||
|
providerWork,
|
||||||
|
executionWork
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
ruleId: CONSENT_DIFF_RULE_ID,
|
||||||
|
ruleVersion: CONSENT_DIFF_RULE_VERSION,
|
||||||
|
derivedAt,
|
||||||
|
captureSessionId,
|
||||||
|
sources: {
|
||||||
|
providerAnnouncement: buildConsentDiffSourceReference(
|
||||||
|
providerAnnouncement
|
||||||
|
),
|
||||||
|
consentExecution: buildConsentDiffSourceReference(consentExecution)
|
||||||
|
},
|
||||||
|
sourceSelection: {
|
||||||
|
providerAnnouncement:
|
||||||
|
"first_provider_announcement_for_capture_session_available_in_memory",
|
||||||
|
consentExecution: "current_useractioncomplete_execution_event"
|
||||||
|
},
|
||||||
|
comparisonAxes: [
|
||||||
|
...CONSENT_DIFF_SCALAR_AXES,
|
||||||
|
...CONSENT_DIFF_OBJECT_AXES
|
||||||
|
],
|
||||||
|
axes,
|
||||||
|
notes: buildConsentDiffNotes(providerAnnouncement, consentExecution)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildConsentDiffWorkCopy(eventRecord, rawTcData) {
|
||||||
|
return {
|
||||||
|
eventRecord: cloneConsentDiffValue(eventRecord ?? null),
|
||||||
|
rawTcData: rawTcData ?? null
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function compareConsentDiffScalarAxis(axis, providerWork, executionWork) {
|
||||||
|
const providerValue = readConsentDiffAxisValue(providerWork, axis);
|
||||||
|
const executionValue = readConsentDiffAxisValue(executionWork, axis);
|
||||||
|
|
||||||
|
return {
|
||||||
|
kind: "scalar",
|
||||||
|
status: getConsentDiffScalarStatus(providerValue, executionValue),
|
||||||
|
provider: buildConsentDiffAxisSide(providerValue),
|
||||||
|
execution: buildConsentDiffAxisSide(executionValue)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function compareConsentDiffObjectAxis(axis, providerWork, executionWork) {
|
||||||
|
const providerValue = readConsentDiffAxisValue(providerWork, axis);
|
||||||
|
const executionValue = readConsentDiffAxisValue(executionWork, axis);
|
||||||
|
const providerObject = isConsentDiffPlainObject(providerValue.value)
|
||||||
|
? providerValue.value
|
||||||
|
: null;
|
||||||
|
const executionObject = isConsentDiffPlainObject(executionValue.value)
|
||||||
|
? executionValue.value
|
||||||
|
: null;
|
||||||
|
const providerKeys = providerObject ? Object.keys(providerObject).sort() : [];
|
||||||
|
const executionKeys = executionObject ? Object.keys(executionObject).sort() : [];
|
||||||
|
const allKeys = Array.from(new Set([...providerKeys, ...executionKeys])).sort();
|
||||||
|
const added = [];
|
||||||
|
const removed = [];
|
||||||
|
const changed = [];
|
||||||
|
const unchanged = [];
|
||||||
|
|
||||||
|
allKeys.forEach((key) => {
|
||||||
|
const inProvider = providerObject
|
||||||
|
? Object.prototype.hasOwnProperty.call(providerObject, key)
|
||||||
|
: false;
|
||||||
|
const inExecution = executionObject
|
||||||
|
? Object.prototype.hasOwnProperty.call(executionObject, key)
|
||||||
|
: false;
|
||||||
|
|
||||||
|
if (inProvider && !inExecution) {
|
||||||
|
removed.push({
|
||||||
|
key,
|
||||||
|
providerValue: cloneConsentDiffValue(providerObject[key])
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!inProvider && inExecution) {
|
||||||
|
added.push({
|
||||||
|
key,
|
||||||
|
executionValue: cloneConsentDiffValue(executionObject[key])
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
stableConsentDiffValue(providerObject[key]) ===
|
||||||
|
stableConsentDiffValue(executionObject[key])
|
||||||
|
) {
|
||||||
|
unchanged.push(key);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
changed.push({
|
||||||
|
key,
|
||||||
|
providerValue: cloneConsentDiffValue(providerObject[key]),
|
||||||
|
executionValue: cloneConsentDiffValue(executionObject[key])
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
kind: "object",
|
||||||
|
status: getConsentDiffObjectStatus(
|
||||||
|
providerValue,
|
||||||
|
executionValue,
|
||||||
|
added,
|
||||||
|
removed,
|
||||||
|
changed
|
||||||
|
),
|
||||||
|
provider: {
|
||||||
|
present: providerValue.present,
|
||||||
|
sourcePath: providerValue.sourcePath,
|
||||||
|
keys: providerKeys
|
||||||
|
},
|
||||||
|
execution: {
|
||||||
|
present: executionValue.present,
|
||||||
|
sourcePath: executionValue.sourcePath,
|
||||||
|
keys: executionKeys
|
||||||
|
},
|
||||||
|
addedKeys: added,
|
||||||
|
removedKeys: removed,
|
||||||
|
changedKeys: changed,
|
||||||
|
unchangedKeys: unchanged,
|
||||||
|
counts: {
|
||||||
|
providerKeys: providerKeys.length,
|
||||||
|
executionKeys: executionKeys.length,
|
||||||
|
added: added.length,
|
||||||
|
removed: removed.length,
|
||||||
|
changed: changed.length,
|
||||||
|
unchanged: unchanged.length
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function readConsentDiffAxisValue(workCopy, axis) {
|
||||||
|
const rawValue = readConsentDiffPath(workCopy.rawTcData, axis);
|
||||||
|
|
||||||
|
if (rawValue.present) {
|
||||||
|
return {
|
||||||
|
...rawValue,
|
||||||
|
sourcePath: `rawTcData.${axis}`
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const eventValue = readConsentDiffPath(workCopy.eventRecord, axis);
|
||||||
|
|
||||||
|
if (eventValue.present) {
|
||||||
|
return {
|
||||||
|
...eventValue,
|
||||||
|
sourcePath: axis
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
present: false,
|
||||||
|
value: undefined,
|
||||||
|
sourcePath: null
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function readConsentDiffPath(value, path) {
|
||||||
|
if (value === null || value === undefined) {
|
||||||
|
return {
|
||||||
|
present: false,
|
||||||
|
value: undefined
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const parts = path.split(".");
|
||||||
|
let current = value;
|
||||||
|
|
||||||
|
for (const part of parts) {
|
||||||
|
if (
|
||||||
|
current === null ||
|
||||||
|
current === undefined ||
|
||||||
|
!Object.prototype.hasOwnProperty.call(Object(current), part)
|
||||||
|
) {
|
||||||
|
return {
|
||||||
|
present: false,
|
||||||
|
value: undefined
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
current = current[part];
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
present: true,
|
||||||
|
value: cloneConsentDiffValue(current)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function getConsentDiffScalarStatus(providerValue, executionValue) {
|
||||||
|
if (!providerValue.present && !executionValue.present) {
|
||||||
|
return "absent";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (providerValue.present && !executionValue.present) {
|
||||||
|
return "removed";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!providerValue.present && executionValue.present) {
|
||||||
|
return "added";
|
||||||
|
}
|
||||||
|
|
||||||
|
return stableConsentDiffValue(providerValue.value) ===
|
||||||
|
stableConsentDiffValue(executionValue.value)
|
||||||
|
? "unchanged"
|
||||||
|
: "changed";
|
||||||
|
}
|
||||||
|
|
||||||
|
function getConsentDiffObjectStatus(
|
||||||
|
providerValue,
|
||||||
|
executionValue,
|
||||||
|
added,
|
||||||
|
removed,
|
||||||
|
changed
|
||||||
|
) {
|
||||||
|
if (!providerValue.present && !executionValue.present) {
|
||||||
|
return "absent";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (providerValue.present && !executionValue.present) {
|
||||||
|
return "removed";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!providerValue.present && executionValue.present) {
|
||||||
|
return "added";
|
||||||
|
}
|
||||||
|
|
||||||
|
return added.length === 0 && removed.length === 0 && changed.length === 0
|
||||||
|
? "unchanged"
|
||||||
|
: "changed";
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildConsentDiffAxisSide(axisValue) {
|
||||||
|
return {
|
||||||
|
present: axisValue.present,
|
||||||
|
sourcePath: axisValue.sourcePath,
|
||||||
|
value: axisValue.present ? cloneConsentDiffValue(axisValue.value) : null
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildConsentDiffSourceReference(eventRecord) {
|
||||||
|
if (!eventRecord) {
|
||||||
|
return {
|
||||||
|
available: false,
|
||||||
|
reason: "missing_source_event"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
available: true,
|
||||||
|
store: "consent_events",
|
||||||
|
id: eventRecord.id ?? null,
|
||||||
|
eventType: eventRecord.eventType ?? null,
|
||||||
|
rawEventName: eventRecord.rawEventName ?? null,
|
||||||
|
capturedAt: eventRecord.capturedAt ?? null,
|
||||||
|
recordedAt: eventRecord.recordedAt ?? null,
|
||||||
|
captureSessionId: eventRecord.captureSessionId ?? null
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildConsentDiffNotes(providerAnnouncement, consentExecution) {
|
||||||
|
const notes = [];
|
||||||
|
|
||||||
|
if (!providerAnnouncement) {
|
||||||
|
notes.push("provider_announcement_source_missing");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!consentExecution) {
|
||||||
|
notes.push("consent_execution_source_missing");
|
||||||
|
}
|
||||||
|
|
||||||
|
notes.push("primary_evidence_not_modified");
|
||||||
|
notes.push("no_legal_assessment");
|
||||||
|
notes.push("no_gvl_semantic_assessment");
|
||||||
|
|
||||||
|
return notes;
|
||||||
|
}
|
||||||
|
|
||||||
|
function stableConsentDiffValue(value) {
|
||||||
|
if (value === undefined) {
|
||||||
|
return "[[undefined]]";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value === null || typeof value !== "object") {
|
||||||
|
return JSON.stringify(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Array.isArray(value)) {
|
||||||
|
return `[${value.map((item) => stableConsentDiffValue(item)).join(",")}]`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return `{${Object.keys(value)
|
||||||
|
.sort()
|
||||||
|
.map((key) => `${JSON.stringify(key)}:${stableConsentDiffValue(value[key])}`)
|
||||||
|
.join(",")}}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function cloneConsentDiffValue(value) {
|
||||||
|
if (value === undefined) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value === null || typeof value !== "object") {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return JSON.parse(JSON.stringify(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
function isConsentDiffPlainObject(value) {
|
||||||
|
return (
|
||||||
|
value !== null &&
|
||||||
|
typeof value === "object" &&
|
||||||
|
!Array.isArray(value)
|
||||||
|
);
|
||||||
|
}
|
||||||
In neuem Issue referenzieren
Einen Benutzer sperren