From 98bce1b0da675715b2e5482c0ad61ba21135f62f Mon Sep 17 00:00:00 2001
From: Server-Bibliothek <server-bibliothek@lokal>
Date: Di, 04 Aug 2026 07:00:04 +0200
Subject: [PATCH] Add a desktop client that knows what is installed locally
---
packages/bibliothek-server/src/abgleich.ts | 108 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 108 insertions(+), 0 deletions(-)
diff --git a/packages/bibliothek-server/src/abgleich.ts b/packages/bibliothek-server/src/abgleich.ts
new file mode 100644
index 0000000..36f8c36
--- /dev/null
+++ b/packages/bibliothek-server/src/abgleich.ts
@@ -0,0 +1,108 @@
+import * as fs from 'fs';
+import * as path from 'path';
+import type { AbgleichErgebnis, Software } from 'bibliothek-types';
+import { DATEIEN_ORDNER, QUELLEN_ORDNER, abgleichSpeichern } from './datenbank';
+import { bezugsquelleFuer, type QuellenAbgleich } from './bezugsquellen';
+import { pruefeSignatur, weichtHerausgeberAb } from './signatur';
+import { alsUmgebung, ladeGeheimnisse } from './geheimnisse';
+import { gitSshBefehl } from './konfiguration';
+
+/** Größe der aktuell bereitgestellten Datei — Grundlage der Plausibilitätsprüfung. */
+function bisherigeGroesse(software: Software): number {
+ if (!software.dateiname) {
+ return 0;
+ }
+ const pfad = path.join(DATEIEN_ORDNER, String(software.id), software.dateiname);
+ return fs.existsSync(pfad) ? fs.statSync(pfad).size : 0;
+}
+
+/** Unveränderten Stand zurückschreiben (bei Misserfolg oder unbekannter Quelle). */
+function unveraendert(software: Software, meldung: string, version = software.version): AbgleichErgebnis {
+ return {
+ version,
+ dateiname: software.dateiname,
+ erfolg: false,
+ meldung,
+ geaendert: false,
+ signaturStatus: software.signaturStatus,
+ signaturHerausgeber: software.signaturHerausgeber,
+ veroeffentlichtAm: software.veroeffentlichtAm,
+ benoetigteGeheimnisse: software.benoetigteGeheimnisse,
+ };
+}
+
+/** Gleicht eine Software mit ihrer Bezugsquelle ab und speichert das Ergebnis zurück. */
+export async function gleicheSoftwareAb(software: Software): Promise<void> {
+ if (software.quelleTyp === 'manuell') {
+ return; // Datei wird von Hand hinterlegt – es gibt nichts abzugleichen
+ }
+ if (!software.quelleTyp || !software.quelleWert) {
+ return; // keine Quelle gesetzt – nichts zu holen
+ }
+ const quelle = bezugsquelleFuer(software.quelleTyp);
+ if (!quelle) {
+ abgleichSpeichern(software.id, unveraendert(software, `Unbekannte Bezugsquelle: ${software.quelleTyp}`));
+ return;
+ }
+
+ const zielordner = path.join(DATEIEN_ORDNER, String(software.id));
+ const ergebnis = await quelle.gleicheAb({
+ wert: software.quelleWert,
+ aktuelleVersion: software.version,
+ zielordner,
+ arbeitsordner: path.join(QUELLEN_ORDNER, String(software.id)),
+ bauBefehl: software.bauBefehl,
+ bauErgebnis: software.bauErgebnis,
+ vorherigeGroesse: bisherigeGroesse(software),
+ geheimnisse: alsUmgebung(ladeGeheimnisse(software.id)),
+ gitSshBefehl: gitSshBefehl(),
+ });
+
+ if (!ergebnis.erfolg) {
+ abgleichSpeichern(software.id, unveraendert(software, ergebnis.meldung, ergebnis.version));
+ return;
+ }
+
+ abgleichSpeichern(software.id, await mitSignaturbefund(software, ergebnis, zielordner));
+}
+
+/**
+ * Ergänzt das Abgleich-Ergebnis um die Windows-Signatur der bereitgestellten Datei.
+ * Ist ein Signaturgeber erwartet und weicht der gefundene ab, wird die Datei nicht
+ * zum Download freigegeben (`dateiname` bleibt leer) — sie bleibt aber zur Ansicht liegen.
+ */
+async function mitSignaturbefund(software: Software, ergebnis: QuellenAbgleich, zielordner: string): Promise<AbgleichErgebnis> {
+ const befund = await pruefeSignatur(path.join(zielordner, ergebnis.dateiname));
+ const gemeinsam = {
+ version: ergebnis.version,
+ signaturStatus: befund.status,
+ signaturHerausgeber: befund.herausgeber,
+ veroeffentlichtAm: ergebnis.veroeffentlichtAm ?? software.veroeffentlichtAm,
+ benoetigteGeheimnisse: ergebnis.benoetigteGeheimnisse ?? software.benoetigteGeheimnisse,
+ };
+ if (weichtHerausgeberAb(software.erwarteterHerausgeber, befund.herausgeber)) {
+ return {
+ ...gemeinsam,
+ dateiname: '', // nicht ausliefern, bis das geklärt ist
+ erfolg: false,
+ meldung: `Signatur weicht ab: erwartet „${software.erwarteterHerausgeber}", gefunden „${befund.herausgeber || 'unsigniert'}" (${befund.status}). Die Datei wird nicht zum Download angeboten.`,
+ geaendert: false,
+ };
+ }
+ return {
+ ...gemeinsam,
+ dateiname: ergebnis.dateiname,
+ erfolg: true,
+ meldung: ergebnis.meldung,
+ geaendert: ergebnis.geaendert,
+ };
+}
+
+/** Gleicht nacheinander alle Einträge mit gesetzter Quelle ab (täglicher Auto-Check). */
+export async function gleicheAlleAb(alle: Software[]): Promise<void> {
+ for (const software of alle) {
+ if (software.quelleTyp && software.quelleWert) {
+ await gleicheSoftwareAb(software);
+ }
+ }
+}
--
Gitblit v1.9.3