Server-Bibliothek
vor 18 Std. 98bce1b0da675715b2e5482c0ad61ba21135f62f
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
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);
    }
  }
}