Server-Bibliothek
vor 18 Std. 1f44739ba685cd77dc804adcc58fbf584b21e52b
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
import * as fs from 'fs';
import * as path from 'path';
import type { Einstellungen } from 'bibliothek-types';
import { anwendungsDatenOrdner } from './pfade';
 
/**
 * Einstellungen liegen in `konfiguration.json` neben der Anwendung. Die Datei wird
 * beim ersten Start mit Standardwerten angelegt und kann über die Oberfläche
 * (nur lokal am Server) oder von Hand gepflegt werden.
 *
 * Umgebungsvariablen haben Vorrang — praktisch für abweichende Testläufe.
 */
 
const STANDARD_EINSTELLUNGEN: Einstellungen = {
  datenOrdner: '', // leer = Unterordner „data" im Anwendungsdaten-Ordner
  port: 3000,
  gitBenutzer: '', // leer = SSH-Konfiguration des Dienstbenutzers entscheidet
  gitSchluessel: '',
};
 
const konfigurationsPfad = path.join(anwendungsDatenOrdner(), 'konfiguration.json');
 
/** Liest die Konfigurationsdatei (und legt sie beim ersten Start an). */
function leseOderErzeuge(): Einstellungen {
  try {
    if (fs.existsSync(konfigurationsPfad)) {
      return normalisiere(JSON.parse(fs.readFileSync(konfigurationsPfad, 'utf8')) as Partial<Einstellungen>);
    }
    const standard = { ...STANDARD_EINSTELLUNGEN };
    schreibeDatei(standard);
    return standard;
  } catch (fehler) {
    console.warn(`konfiguration.json konnte nicht gelesen werden, Standardwerte greifen: ${String(fehler)}`);
    return { ...STANDARD_EINSTELLUNGEN };
  }
}
 
// Beim Laden des Moduls einlesen, damit auch die Datenbank-Schicht schon den
// konfigurierten Ordner sieht (sie wird beim Start direkt initialisiert).
let gelesene: Einstellungen = leseOderErzeuge();
 
/** Speichert geänderte Einstellungen. Der Datenordner wirkt erst nach einem Neustart. */
export function speichereEinstellungen(neue: Partial<Einstellungen>): Einstellungen {
  gelesene = normalisiere({ ...gelesene, ...neue });
  schreibeDatei(gelesene);
  return gelesene;
}
 
export function aktuelleEinstellungen(): Einstellungen {
  return gelesene;
}
 
export function konfigurationsDatei(): string {
  return konfigurationsPfad;
}
 
/** Tatsächlich genutzter Datenordner — Umgebungsvariable vor Einstellung vor Standard. */
export function effektiverDatenOrdner(): string {
  const ausUmgebung = process.env.DATEN_ORDNER?.trim();
  if (ausUmgebung) {
    return path.resolve(ausUmgebung);
  }
  if (gelesene.datenOrdner.trim()) {
    return path.resolve(gelesene.datenOrdner.trim());
  }
  return path.join(anwendungsDatenOrdner(), 'data');
}
 
/** Tatsächlich genutzter Port — Umgebungsvariable vor Einstellung vor Standard. */
export function effektiverPort(): number {
  const ausUmgebung = Number(process.env.PORT);
  if (Number.isInteger(ausUmgebung) && ausUmgebung > 0) {
    return ausUmgebung;
  }
  return gelesene.port;
}
 
function normalisiere(eingabe: Partial<Einstellungen>): Einstellungen {
  const port = Number(eingabe.port);
  return {
    datenOrdner: typeof eingabe.datenOrdner === 'string' ? eingabe.datenOrdner.trim() : '',
    port: Number.isInteger(port) && port > 0 && port < 65536 ? port : STANDARD_EINSTELLUNGEN.port,
    // Nur was als SSH-Benutzername taugt — schützt zugleich vor Einschleusen in die Befehlszeile.
    gitBenutzer: /^[A-Za-z0-9._-]*$/.test(String(eingabe.gitBenutzer ?? '').trim()) ? String(eingabe.gitBenutzer ?? '').trim() : '',
    gitSchluessel: String(eingabe.gitSchluessel ?? '').trim(),
  };
}
 
/**
 * Baut den SSH-Aufruf für Git aus den Einstellungen. Leer, wenn nichts gepflegt ist —
 * dann greift die SSH-Konfiguration des Dienstbenutzers wie bisher.
 */
export function gitSshBefehl(): string {
  const teile = ['ssh'];
  if (gelesene.gitBenutzer) {
    teile.push('-o', `User=${gelesene.gitBenutzer}`);
  }
  if (gelesene.gitSchluessel) {
    teile.push('-i', `"${gelesene.gitSchluessel.replace(/\\/g, '/')}"`);
  }
  return teile.length > 1 ? teile.join(' ') : '';
}
 
function schreibeDatei(einstellungen: Einstellungen): void {
  fs.mkdirSync(path.dirname(konfigurationsPfad), { recursive: true });
  fs.writeFileSync(konfigurationsPfad, `${JSON.stringify(einstellungen, null, 2)}\n`);
}