feat(verzeichnis): LDAP-Abgleich, Zeitplan, CSV-Import und Log
Quelle anlegen, Verbindung testen, nach Zeitplan oder auf Knopfdruck abgleichen. Gelesen wird seitenweise mit searchPaginated, objectGUID kommt als Puffer und wird gemischt-endian zur GUID umsortiert. Wer im Verzeichnis verschwindet, wird hier inaktiv und nie geloescht. Drei Regeln verhindern, dass eine kaputte Eingabe wie "alle sind gegangen" aussieht: laesst sich kein einziger Eintrag zuordnen, wird niemand deaktiviert; uebersprungene Eintraege werden am dn erkannt und ausgenommen; eine von Hand angelegte Person wird uebernommen statt verdoppelt. Der Zeitplan laeuft ueber node-cron im selben Prozess, gestartet aus src/instrumentation.ts, und nimmt keine eigene Sperre - die liegt in der Datenbank, damit zwei Instanzen sich einig sind. Closes #16 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
ab5777a57e
commit
16059e7846
@@ -0,0 +1,65 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { GuidFehler, guidAusBytes } from "@/lib/ldap-guid";
|
||||
|
||||
/**
|
||||
* `objectGUID` als GUID-Zeichenkette (#016).
|
||||
*
|
||||
* Diese Umsortierung ist der Grund, warum die Kennung ueberhaupt eine eigene
|
||||
* Datei hat: schlaegt sie fehl, sieht das Ergebnis trotzdem wie eine GUID aus.
|
||||
* Der Abgleich wuerde dann bei jedem Lauf dieselben Personen neu anlegen, weil
|
||||
* die Kennung zwar stabil, aber gegen `Get-ADUser` nicht auffindbar waere — ein
|
||||
* Fehler, der erst auffaellt, wenn jemand mit dem AD vergleicht.
|
||||
*
|
||||
* Die erwarteten Zeichenketten sind mit Pythons `uuid.UUID(bytes_le=…)`
|
||||
* ausgerechnet, also mit einer unabhaengigen Umsetzung derselben Reihenfolge.
|
||||
*/
|
||||
|
||||
describe("guidAusBytes", () => {
|
||||
it("ordnet die ersten drei Gruppen little-endian, den Rest in Leserichtung", () => {
|
||||
// Der aufschlussreichste Vektor: die Bytes 00…0f. An der Ausgabe ist die
|
||||
// Umsortierung mit dem Auge nachzuvollziehen.
|
||||
const bytes = Uint8Array.from([
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
]);
|
||||
expect(guidAusBytes(bytes)).toBe("03020100-0504-0706-0809-0a0b0c0d0e0f");
|
||||
});
|
||||
|
||||
it("liest den Byte-Vektor einer echten AD-Kennung", () => {
|
||||
// Dieselben Bytes stehen base64-kodiert im Fixture des Testcontainers
|
||||
// (tests/fixtures/ldap/daten/50-personen.ldif, „Maria Huber“).
|
||||
const bytes = Uint8Array.from(Buffer.from("EEMHXzU8HUqDb6UPUV56NQ==", "base64"));
|
||||
expect(guidAusBytes(bytes)).toBe("5f074310-3c35-4a1d-836f-a50f515e7a35");
|
||||
});
|
||||
|
||||
it("liefert bei denselben Bytes immer dieselbe Zeichenkette", () => {
|
||||
const bytes = Uint8Array.from(Buffer.from("nEA+HXqyyUux5vCiw9Tl9g==", "base64"));
|
||||
expect(guidAusBytes(bytes)).toBe(guidAusBytes(bytes));
|
||||
expect(guidAusBytes(Uint8Array.from(bytes))).toBe("1d3e409c-b27a-4bc9-b1e6-f0a2c3d4e5f6");
|
||||
});
|
||||
|
||||
it("schreibt fuehrende Nullen mit", () => {
|
||||
// Ohne padStart waere daraus "0-0-0-0-0"; die Kennung waere kuerzer als eine
|
||||
// GUID und passte doch zu einem Konto.
|
||||
expect(guidAusBytes(new Uint8Array(16))).toBe("00000000-0000-0000-0000-000000000000");
|
||||
});
|
||||
|
||||
it("gibt Klein- und nicht Grossbuchstaben aus", () => {
|
||||
const bytes = Uint8Array.from(Buffer.from("/+7dzLuqmYh3ZlVEMyIRAA==", "base64"));
|
||||
const guid = guidAusBytes(bytes);
|
||||
expect(guid).toBe("ccddeeff-aabb-8899-7766-554433221100");
|
||||
expect(guid).toBe(guid.toLowerCase());
|
||||
});
|
||||
|
||||
it("hat die Form 8-4-4-4-12", () => {
|
||||
const guid = guidAusBytes(Uint8Array.from(Buffer.from("AQIDBAUGBwgJCgsMDQ4PEA==", "base64")));
|
||||
expect(guid).toMatch(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/u);
|
||||
});
|
||||
|
||||
it("wirft bei falscher Laenge statt eine halbe Kennung zu liefern", () => {
|
||||
// Genau der Fall, der ohne explicitBufferAttributes entsteht: die 16 Bytes
|
||||
// wurden als UTF-8 gelesen und dabei veraendert.
|
||||
expect(() => guidAusBytes(new Uint8Array(15))).toThrow(GuidFehler);
|
||||
expect(() => guidAusBytes(new Uint8Array(0))).toThrow(GuidFehler);
|
||||
expect(() => guidAusBytes(new Uint8Array(36))).toThrow(/16 Bytes/u);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user