verify meldet, dass die Kette neu berechnet wurde
Im Betrieb entdeckt, nicht im Test. Das Staging-Gegenbuch meldete "Der beglaubigte Eintrag 5352 existiert nicht mehr". Rekonstruktion aus dem Protokoll: am 22.08. wurden die Aufbewahrungsfristen auf 0 gesetzt, zwei Cleanups loeschten 3155 Eintraege (id 1-5356), danach lief ein Rehash. Seither meldet die Pruefung "Alle Eintraege sind unveraendert und lueckenlos verkettet". Wahr - und praktisch das Gegenteil dessen, was ein Leser mitnimmt. Der Rehash verknuepft alles neu; die rund 700 Kettenluecken, die davor bestanden, sind seitdem unsichtbar. Nachweisbar im Vorbefund, den der Rehash selbst mitschreibt (R170-01) - nur schaute den nie jemand an. Das Gegenbuch war der einzige Zeuge; innerhalb des CRM war die Loeschung nicht mehr feststellbar. verifyIntegrity sammelt jetzt die Rehash-Marker; die Antwort enthaelt rehashes[] mit Zeitpunkt, Anzahl, Signatur und Vorbefund. Die Meldung nennt sie IMMER, auch im gruenen Fall, und der Einstiegssatz lautet dann "...lueckenlos verkettet - allerdings erst seit der letzten Neuberechnung". valid bleibt unberuehrt. Ein Rehash ist eine legitime Massnahme; ihn dauerhaft als Befund zu fuehren waere der Dauer-Alarm, den wir mit den beglaubigten Luecken gerade beseitigt haben. Melden, nicht alarmieren. Umgekehrte Beweislast als bei Manifest und Siegel: Dort zaehlen nur signierte Traeger, weil ein gefaelschter Marker Luecken wegerklaeren koennte. Hier erzeugt ein Marker eine Warnung - wuerden nur signierte zaehlen, koennte man einen Rehash unsichtbar machen, indem man seine Signatur zerstoert. Deshalb zaehlt jeder auswertbare Marker; eine fehlende Signatur wird zusaetzlich gemeldet. Getestet ueber HTTP gegen eine Wegwerf-DB mit echtem Rehash ueber den regulaeren Endpunkt: sauberer Vorzustand, Loeschung+Rehash (der Staging-Ablauf im Kleinen), und zerstoerte Signatur. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -273,6 +273,49 @@ export async function verifyIntegrity(req: AuthRequest, res: Response) {
|
|||||||
'Behebbar mit POST /api/audit-logs/seal-backlog {"confirm":"SEAL"}.'
|
'Behebbar mit POST /api/audit-logs/seal-backlog {"confirm":"SEAL"}.'
|
||||||
: '';
|
: '';
|
||||||
|
|
||||||
|
// Eine Neuberechnung der Kette gehoert IMMER erwaehnt – auch und gerade,
|
||||||
|
// wenn sonst alles grün ist. Nach einem Rehash ist die Kette
|
||||||
|
// zwangslaeufig stimmig, auch ueber Loeschungen hinweg. „Lueckenlos
|
||||||
|
// verkettet“ heisst dann nur noch „seit dem Rehash“, und wer das nicht
|
||||||
|
// mitliest, nimmt eine Entwarnung mit, die es so nicht gibt.
|
||||||
|
const rehashText = (() => {
|
||||||
|
if (result.rehashes.length === 0) return '';
|
||||||
|
const letzter = result.rehashes[result.rehashes.length - 1];
|
||||||
|
const datum = new Date(letzter.zeitpunkt).toLocaleString('de-DE', {
|
||||||
|
dateStyle: 'short',
|
||||||
|
timeStyle: 'short',
|
||||||
|
});
|
||||||
|
const wieOft =
|
||||||
|
result.rehashes.length === 1
|
||||||
|
? 'Die Kette wurde einmal neu berechnet'
|
||||||
|
: `Die Kette wurde ${result.rehashes.length}× neu berechnet, zuletzt`;
|
||||||
|
// Nur benennen, was es zu benennen gibt. Bei sauberem Vorzustand ist die
|
||||||
|
// Auskunft „nichts uebertuencht“ selbst eine nuetzliche Information –
|
||||||
|
// ein Rehash ueber einer unbeanstandeten Kette wiegt anders als einer
|
||||||
|
// ueber 700 Luecken.
|
||||||
|
const vb = letzter.vorbefund;
|
||||||
|
const uebertuencht = !vb
|
||||||
|
? ' Der Zustand vor dieser Neuberechnung ist nicht mehr feststellbar.'
|
||||||
|
: vb.manipuliert === 0 && vb.luecken === 0
|
||||||
|
? ' Die Kette war unmittelbar davor unbeanstandet – es wurde nichts überdeckt.'
|
||||||
|
: ' Unmittelbar davor: ' +
|
||||||
|
`${vb.manipuliert} beanstandete${vb.manipuliert === 1 ? 'r Eintrag' : ' Einträge'}` +
|
||||||
|
` und ${vb.luecken} Lücke${vb.luecken === 1 ? '' : 'n'}. ` +
|
||||||
|
'Diese Spuren sind seitdem nicht mehr in der Kette sichtbar, sondern nur noch im ' +
|
||||||
|
`Vorbefund des Rehash-Eintrags (id ${letzter.id}).`;
|
||||||
|
const ohneSignatur = result.rehashes.some((r) => !r.signiert)
|
||||||
|
? ' Achtung: Mindestens ein Rehash-Eintrag trägt keine gültige Signatur.'
|
||||||
|
: '';
|
||||||
|
return (
|
||||||
|
` ⚠ ${wieOft} am ${datum}` +
|
||||||
|
(letzter.neuBerechnet !== null ? ` (${letzter.neuBerechnet} Einträge)` : '') +
|
||||||
|
'. Ein Rehash verknüpft alle Einträge neu – die Aussage dieser Prüfung ' +
|
||||||
|
'reicht deshalb nur bis dorthin zurück, nicht weiter.' +
|
||||||
|
uebertuencht +
|
||||||
|
ohneSignatur
|
||||||
|
);
|
||||||
|
})();
|
||||||
|
|
||||||
// Erneutes Siegeln kann legitim sein, verdient aber einen Blick: es
|
// Erneutes Siegeln kann legitim sein, verdient aber einen Blick: es
|
||||||
// ersetzt die zuvor beglaubigte Wurzel (Pentest R173-03).
|
// ersetzt die zuvor beglaubigte Wurzel (Pentest R173-03).
|
||||||
const mehrfach =
|
const mehrfach =
|
||||||
@@ -303,7 +346,10 @@ export async function verifyIntegrity(req: AuthRequest, res: Response) {
|
|||||||
: beglaubigt > 0
|
: beglaubigt > 0
|
||||||
? 'Alle Einträge sind unverändert. Seit dem Bestandssiegel ist keine neue Lücke ' +
|
? 'Alle Einträge sind unverändert. Seit dem Bestandssiegel ist keine neue Lücke ' +
|
||||||
'entstanden.'
|
'entstanden.'
|
||||||
: 'Alle Einträge sind unverändert und lückenlos verkettet.';
|
: result.rehashes.length > 0
|
||||||
|
? 'Alle Einträge sind unverändert und lückenlos verkettet – allerdings erst ' +
|
||||||
|
'seit der letzten Neuberechnung.'
|
||||||
|
: 'Alle Einträge sind unverändert und lückenlos verkettet.';
|
||||||
|
|
||||||
res.json({
|
res.json({
|
||||||
success: true,
|
success: true,
|
||||||
@@ -319,8 +365,10 @@ export async function verifyIntegrity(req: AuthRequest, res: Response) {
|
|||||||
unexplainedGaps: result.unexplainedGaps,
|
unexplainedGaps: result.unexplainedGaps,
|
||||||
// Alt-Lücken, die das Bestandssiegel als bereits vorhanden beglaubigt.
|
// Alt-Lücken, die das Bestandssiegel als bereits vorhanden beglaubigt.
|
||||||
attestedGaps: result.attestedGaps,
|
attestedGaps: result.attestedGaps,
|
||||||
|
// Protokollierte Neuberechnungen – begrenzen die Reichweite der Aussage.
|
||||||
|
rehashes: result.rehashes,
|
||||||
tampered: tampered > 0,
|
tampered: tampered > 0,
|
||||||
message: message + beglaubigtText + keinSchluessel + siegel + mehrfach,
|
message: message + beglaubigtText + rehashText + keinSchluessel + siegel + mehrfach,
|
||||||
unverifiableEntries: result.unverifiableEntries,
|
unverifiableEntries: result.unverifiableEntries,
|
||||||
// Zustand des Bestandssiegels ueber den nicht signierbaren Altbestand.
|
// Zustand des Bestandssiegels ueber den nicht signierbaren Altbestand.
|
||||||
backlogSealStatus: result.backlogSealStatus,
|
backlogSealStatus: result.backlogSealStatus,
|
||||||
|
|||||||
@@ -909,6 +909,24 @@ export async function verifyIntegrity(fromId?: number, toId?: number): Promise<{
|
|||||||
* nicht mehr (siehe ausfuehrliche Begruendung an der Berechnung unten).
|
* nicht mehr (siehe ausfuehrliche Begruendung an der Berechnung unten).
|
||||||
*/
|
*/
|
||||||
attestedGaps: number[];
|
attestedGaps: number[];
|
||||||
|
/**
|
||||||
|
* Protokollierte Neuberechnungen der Kette (Rehash), aelteste zuerst.
|
||||||
|
*
|
||||||
|
* Ein Rehash verknuepft alle Eintraege neu. Danach ist die Kette
|
||||||
|
* zwangslaeufig stimmig - auch ueber Loeschungen hinweg, die vorher als
|
||||||
|
* Luecken sichtbar waren. „Lueckenlos verkettet“ heisst nach einem Rehash
|
||||||
|
* also nur noch: seit dem Rehash. Wer das nicht mitliest, nimmt eine
|
||||||
|
* Entwarnung mit, die es nicht gibt.
|
||||||
|
*/
|
||||||
|
rehashes: Array<{
|
||||||
|
id: number;
|
||||||
|
zeitpunkt: string;
|
||||||
|
neuBerechnet: number | null;
|
||||||
|
/** Marker mit gueltiger HMAC-Signatur? Siehe Kommentar an der Auswertung. */
|
||||||
|
signiert: boolean;
|
||||||
|
/** Befund unmittelbar VOR dem Rehash - was also uebertuencht wurde. */
|
||||||
|
vorbefund: { manipuliert: number; luecken: number } | null;
|
||||||
|
}>;
|
||||||
/**
|
/**
|
||||||
* Zustand des Bestandssiegels ueber den nicht signierbaren Altbestand.
|
* Zustand des Bestandssiegels ueber den nicht signierbaren Altbestand.
|
||||||
* `kein_siegel` = nie erstellt. `entfernt` = Blaetter vorhanden, aber kein
|
* `kein_siegel` = nie erstellt. `entfernt` = Blaetter vorhanden, aber kein
|
||||||
@@ -1044,6 +1062,68 @@ export async function verifyIntegrity(fromId?: number, toId?: number): Promise<{
|
|||||||
const gapErklaert = (prevId: number, curId: number) =>
|
const gapErklaert = (prevId: number, curId: number) =>
|
||||||
deletionRanges.some((r) => r.from <= curId && r.to >= prevId);
|
deletionRanges.some((r) => r.from <= curId && r.to >= prevId);
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
// Protokollierte Neuberechnungen (Rehash) einsammeln.
|
||||||
|
//
|
||||||
|
// Ein Rehash macht die Kette rechnerisch stimmig - auch dort, wo vorher
|
||||||
|
// Loeschungen als Luecken sichtbar waren. Genau das ist auf Staging passiert:
|
||||||
|
// zwei Cleanups mit Aufbewahrung 0 entfernten 3155 Eintraege, der folgende
|
||||||
|
// Rehash liess rund 700 Kettenluecken verschwinden, und die Pruefung meldete
|
||||||
|
// danach „unveraendert und lueckenlos verkettet“. Wahr - und trotzdem das
|
||||||
|
// Gegenteil dessen, was ein Leser mitnimmt.
|
||||||
|
//
|
||||||
|
// Umgekehrte Beweislast als bei Manifest und Siegel: Dort zaehlen NUR
|
||||||
|
// signierte Traeger, weil ein gefaelschter Marker Luecken wegerklaeren
|
||||||
|
// koennte - Misstrauen ist die sichere Richtung. Hier erzeugt ein Marker eine
|
||||||
|
// WARNUNG. Wuerden wir nur signierte gelten lassen, koennte jemand einen
|
||||||
|
// Rehash unsichtbar machen, indem er dessen Signatur zerstoert. Deshalb
|
||||||
|
// zaehlt hier jeder auswertbare Marker; ob er signiert ist, wird nur
|
||||||
|
// mitgeteilt.
|
||||||
|
const rehashKandidaten = await prisma.auditLog.findMany({
|
||||||
|
where: { resourceType: 'AuditLog', action: 'UPDATE', endpoint: '/api/audit-logs/rehash' },
|
||||||
|
orderBy: { id: 'asc' },
|
||||||
|
});
|
||||||
|
const rehashSchluessel = [auditHmacKey(), ...auditHmacKeysOld()].filter(
|
||||||
|
(k): k is string => !!k,
|
||||||
|
);
|
||||||
|
const rehashes: Array<{
|
||||||
|
id: number;
|
||||||
|
zeitpunkt: string;
|
||||||
|
neuBerechnet: number | null;
|
||||||
|
signiert: boolean;
|
||||||
|
vorbefund: { manipuliert: number; luecken: number } | null;
|
||||||
|
}> = [];
|
||||||
|
for (const row of rehashKandidaten) {
|
||||||
|
let neuBerechnet: number | null = null;
|
||||||
|
let vorbefund: { manipuliert: number; luecken: number } | null = null;
|
||||||
|
try {
|
||||||
|
const nach = JSON.parse(row.changesAfter || '{}');
|
||||||
|
if (typeof nach.neuBerechnet !== 'number') continue; // kein Rehash-Marker
|
||||||
|
neuBerechnet = nach.neuBerechnet;
|
||||||
|
const vor = JSON.parse(row.changesBefore || '{}');
|
||||||
|
if (Array.isArray(vor.manipuliert) && Array.isArray(vor.ketten_luecken)) {
|
||||||
|
vorbefund = {
|
||||||
|
manipuliert: vor.manipuliert.length,
|
||||||
|
luecken: vor.ketten_luecken.length,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const signiert =
|
||||||
|
row.hashVersion >= 3 &&
|
||||||
|
rehashSchluessel.some(
|
||||||
|
(k) => row.hash === generateHashV3(row as unknown as AuditHashV2Input, k),
|
||||||
|
);
|
||||||
|
rehashes.push({
|
||||||
|
id: row.id,
|
||||||
|
zeitpunkt: row.createdAt.toISOString(),
|
||||||
|
neuBerechnet,
|
||||||
|
signiert,
|
||||||
|
vorbefund,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const tamperedEntries: number[] = [];
|
const tamperedEntries: number[] = [];
|
||||||
const chainGaps: number[] = [];
|
const chainGaps: number[] = [];
|
||||||
const unexplainedGaps: number[] = [];
|
const unexplainedGaps: number[] = [];
|
||||||
@@ -1349,6 +1429,7 @@ export async function verifyIntegrity(fromId?: number, toId?: number): Promise<{
|
|||||||
unexplainedGaps,
|
unexplainedGaps,
|
||||||
unverifiableEntries,
|
unverifiableEntries,
|
||||||
attestedGaps,
|
attestedGaps,
|
||||||
|
rehashes,
|
||||||
backlogSealStatus,
|
backlogSealStatus,
|
||||||
backlogTampered,
|
backlogTampered,
|
||||||
backlogMissing,
|
backlogMissing,
|
||||||
|
|||||||
@@ -97,6 +97,42 @@ isolierte Instanz (keine Multi-Tenancy im Code), Provisioning + Abrechnung
|
|||||||
|
|
||||||
## ✅ Erledigt
|
## ✅ Erledigt
|
||||||
|
|
||||||
|
- [x] **🔍 `verify` meldet jetzt, dass die Kette neu berechnet wurde** (2026-08-26)
|
||||||
|
- **Im Betrieb entdeckt, nicht im Test.** Das Staging-Gegenbuch meldete
|
||||||
|
„Der beglaubigte Eintrag 5352 existiert nicht mehr". Rekonstruktion aus dem
|
||||||
|
Protokoll: am 22.08. wurden die Aufbewahrungsfristen auf **0** gesetzt,
|
||||||
|
zwei Cleanups löschten **3.155** Einträge (id 1–5356), danach lief ein
|
||||||
|
**Rehash**. Seither meldet die Prüfung „Alle Einträge sind unverändert und
|
||||||
|
**lückenlos** verkettet".
|
||||||
|
- Wahr – und praktisch das Gegenteil dessen, was ein Leser mitnimmt. Der
|
||||||
|
Rehash verknüpft alles neu; die rund **700** Kettenlücken, die davor
|
||||||
|
bestanden, sind seitdem unsichtbar. Nachweisbar im Vorbefund, den der
|
||||||
|
Rehash selbst mitschreibt (R170-01) – nur schaute den nie jemand an.
|
||||||
|
- Das Gegenbuch war der einzige Zeuge. Innerhalb des CRM war die Löschung
|
||||||
|
nicht mehr feststellbar.
|
||||||
|
- `verifyIntegrity` sammelt jetzt die Rehash-Marker; die Antwort enthält
|
||||||
|
`rehashes[]` (Zeitpunkt, Anzahl, Signatur, Vorbefund). Die Meldung nennt
|
||||||
|
sie **immer**, auch im grünen Fall, und der Einstiegssatz lautet dann
|
||||||
|
„…lückenlos verkettet – allerdings erst seit der letzten Neuberechnung".
|
||||||
|
- **`valid` bleibt unberührt.** Ein Rehash ist eine legitime Maßnahme; ihn
|
||||||
|
dauerhaft als Befund zu führen wäre der Dauer-Alarm, den wir mit den
|
||||||
|
beglaubigten Lücken gerade beseitigt haben. Melden, nicht alarmieren.
|
||||||
|
- **Umgekehrte Beweislast als bei Manifest und Siegel:** Dort zählen nur
|
||||||
|
signierte Träger, weil ein gefälschter Marker Lücken *wegerklären* könnte.
|
||||||
|
Hier erzeugt ein Marker eine *Warnung* – würden nur signierte zählen,
|
||||||
|
könnte man einen Rehash unsichtbar machen, indem man seine Signatur
|
||||||
|
zerstört. Deshalb zählt jeder auswertbare Marker; fehlende Signatur wird
|
||||||
|
zusätzlich gemeldet.
|
||||||
|
- Getestet über HTTP gegen eine Wegwerf-DB, mit echtem Rehash über den
|
||||||
|
regulären Endpunkt: sauberer Vorzustand → „es wurde nichts überdeckt";
|
||||||
|
Löschung + Rehash (der Staging-Ablauf im Kleinen) → `chainGaps` fällt von
|
||||||
|
1 auf 0, die Meldung nennt Zeitpunkt und Vorbefund; zerstörte Signatur →
|
||||||
|
Marker wird weiterhin gemeldet, mit Hinweis.
|
||||||
|
- Dateien: `backend/src/services/audit.service.ts`,
|
||||||
|
`backend/src/controllers/auditLog.controller.ts`,
|
||||||
|
`frontend/src/services/api.ts`,
|
||||||
|
`frontend/src/pages/settings/AuditIntegrityCard.tsx`
|
||||||
|
|
||||||
- [x] **📄 `status.txt` nennt jetzt den Grund, nicht nur das Etikett** (2026-08-26)
|
- [x] **📄 `status.txt` nennt jetzt den Grund, nicht nur das Etikett** (2026-08-26)
|
||||||
- In der Statusdatei des Gegenbuchs stand für **jeden** Exit-2 derselbe Satz:
|
- In der Statusdatei des Gegenbuchs stand für **jeden** Exit-2 derselbe Satz:
|
||||||
„BEFUND – Widerspruch zwischen CRM und Gegenbuch". Ein echter Widerspruch
|
„BEFUND – Widerspruch zwischen CRM und Gegenbuch". Ein echter Widerspruch
|
||||||
|
|||||||
@@ -126,7 +126,12 @@ export default function AuditIntegrityCard() {
|
|||||||
<div className={`flex items-start gap-4 p-4 rounded-lg border ${stil.box}`}>
|
<div className={`flex items-start gap-4 p-4 rounded-lg border ${stil.box}`}>
|
||||||
<AmpelIcon ampel={ampel} />
|
<AmpelIcon ampel={ampel} />
|
||||||
<div className="min-w-0">
|
<div className="min-w-0">
|
||||||
<p className={`font-medium ${stil.titel}`}>{AMPEL_TITEL[ampel]}</p>
|
<p className={`font-medium ${stil.titel}`}>
|
||||||
|
{AMPEL_TITEL[ampel]}
|
||||||
|
{ampel === 'ok' && ergebnis.rehashes.length > 0 && (
|
||||||
|
<span className="font-normal"> – seit der letzten Neuberechnung</span>
|
||||||
|
)}
|
||||||
|
</p>
|
||||||
<p className={`text-sm mt-1 ${stil.text}`}>{ergebnis.message}</p>
|
<p className={`text-sm mt-1 ${stil.text}`}>{ergebnis.message}</p>
|
||||||
<p className="text-sm text-gray-500 mt-2">
|
<p className="text-sm text-gray-500 mt-2">
|
||||||
{ergebnis.checkedCount.toLocaleString('de-DE')} Einträge geprüft ·
|
{ergebnis.checkedCount.toLocaleString('de-DE')} Einträge geprüft ·
|
||||||
@@ -156,9 +161,36 @@ export default function AuditIntegrityCard() {
|
|||||||
<Zahl label="Ohne Schlüssel nicht prüfbar" ids={ergebnis.unverifiableEntries} ton="text-gray-700" />
|
<Zahl label="Ohne Schlüssel nicht prüfbar" ids={ergebnis.unverifiableEntries} ton="text-gray-700" />
|
||||||
{ergebnis.tamperedEntries.length === 0 &&
|
{ergebnis.tamperedEntries.length === 0 &&
|
||||||
ergebnis.chainGaps.length === 0 &&
|
ergebnis.chainGaps.length === 0 &&
|
||||||
ergebnis.unverifiableEntries.length === 0 && (
|
ergebnis.unverifiableEntries.length === 0 &&
|
||||||
|
ergebnis.rehashes.length === 0 && (
|
||||||
<p className="text-sm text-gray-500 italic">Nichts zu berichten.</p>
|
<p className="text-sm text-gray-500 italic">Nichts zu berichten.</p>
|
||||||
)}
|
)}
|
||||||
|
{ergebnis.rehashes.length > 0 && (
|
||||||
|
<div className="pt-2 border-t mt-2">
|
||||||
|
<p className="text-sm font-medium text-gray-700">Neuberechnungen der Kette</p>
|
||||||
|
{ergebnis.rehashes.map((r) => (
|
||||||
|
<p key={r.id} className="text-sm text-gray-600 mt-1">
|
||||||
|
{new Date(r.zeitpunkt).toLocaleString('de-DE')} · Eintrag {r.id}
|
||||||
|
{r.neuBerechnet !== null && ` · ${r.neuBerechnet} Einträge neu verkettet`}
|
||||||
|
{r.vorbefund && (
|
||||||
|
<span className="text-gray-500">
|
||||||
|
{' '}· davor: {r.vorbefund.manipuliert} beanstandet,{' '}
|
||||||
|
{r.vorbefund.luecken} Lücken
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
{!r.signiert && (
|
||||||
|
<span className="text-red-700"> · ohne gültige Signatur</span>
|
||||||
|
)}
|
||||||
|
</p>
|
||||||
|
))}
|
||||||
|
<p className="text-xs text-gray-500 mt-2">
|
||||||
|
Ein Rehash verknüpft alle Einträge neu. Was davor als Lücke oder
|
||||||
|
Beanstandung sichtbar war, ist danach nicht mehr in der Kette zu sehen –
|
||||||
|
nur noch im Vorbefund des jeweiligen Eintrags. Die Aussage dieser Prüfung
|
||||||
|
reicht deshalb bis zur letzten Neuberechnung zurück, nicht weiter.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
<p className="text-xs text-gray-500 pt-2">
|
<p className="text-xs text-gray-500 pt-2">
|
||||||
<strong>Verändert</strong> heißt: der Inhalt einer bestehenden Zeile passt nicht
|
<strong>Verändert</strong> heißt: der Inhalt einer bestehenden Zeile passt nicht
|
||||||
mehr zu ihrer Prüfsumme – das ist ernst.
|
mehr zu ihrer Prüfsumme – das ist ernst.
|
||||||
|
|||||||
@@ -1749,6 +1749,18 @@ export interface IntegrityResult {
|
|||||||
unexplainedGaps: number[];
|
unexplainedGaps: number[];
|
||||||
/** Alt-Luecken, die das Bestandssiegel als bereits vorhanden beglaubigt. */
|
/** Alt-Luecken, die das Bestandssiegel als bereits vorhanden beglaubigt. */
|
||||||
attestedGaps: number[];
|
attestedGaps: number[];
|
||||||
|
/**
|
||||||
|
* Protokollierte Neuberechnungen der Kette. Nach einem Rehash ist die Kette
|
||||||
|
* zwangslaeufig stimmig - auch ueber Loeschungen hinweg. Die Aussage der
|
||||||
|
* Pruefung reicht dann nur bis zur letzten Neuberechnung zurueck.
|
||||||
|
*/
|
||||||
|
rehashes: Array<{
|
||||||
|
id: number;
|
||||||
|
zeitpunkt: string;
|
||||||
|
neuBerechnet: number | null;
|
||||||
|
signiert: boolean;
|
||||||
|
vorbefund: { manipuliert: number; luecken: number } | null;
|
||||||
|
}>;
|
||||||
/** Signierte Zeilen, die ohne AUDIT_HMAC_KEY nicht pruefbar sind. */
|
/** Signierte Zeilen, die ohne AUDIT_HMAC_KEY nicht pruefbar sind. */
|
||||||
unverifiableEntries: number[];
|
unverifiableEntries: number[];
|
||||||
backlogSealStatus: 'kein_siegel' | 'intakt' | 'leer' | 'gebrochen' | 'entfernt' | 'nicht_noetig';
|
backlogSealStatus: 'kein_siegel' | 'intakt' | 'leer' | 'gebrochen' | 'entfernt' | 'nicht_noetig';
|
||||||
|
|||||||
Reference in New Issue
Block a user