feat(quick-260914-eym): Mail-Transport je Versand nach Mandant (WINDOWS #30), ldap/digest/matching ueber Systemkontext, vier Tabellen im Werkzeug, Erlaubnisliste vollstaendig
- mail: MailerModule-Fabrik und DB-Startpfad (findFirst beim Boot) ersatzlos entfernt; MailService baut je Versand einen nodemailer-Transport aus getDecryptedSmtpConfig(tenantId) des Empfaenger-Mandanten, Umgebungs-Kette (MAIL_* -> TESSERA_SMTP_* -> localhost:1025) nur als Rueckfall; Fehler weiter verschluckt (T-02-12), close() im finally; neue mail.service.spec.ts (4 Tests, T-GWH-03 geschlossen) - settings: Startpfad-Methode samt vier Spec-Tests geloescht; auth: requestPasswordReset reicht user.tenantId durch (Spec-Zusicherung) - ldap: getAllActiveConfigs und Nachverschluesselung lesen ueber forSystem (zwei Zuweisungen), Schreibzeile je Altzeile ueber forTenant(config.tenantId); Tests 301/306 umgedreht, neuer Altzeilen-Test - tender-digest: Kandidatenabfrage ueber forSystem, Schleife gebunden (+1 Test) - tender-matching: Profilabfrage ueber forSystem, Katalog (D-03) ungebunden (+1 Test) - tender-notifications.integration.spec: Mock um forSystem - Werkzeug: LdapConfig (15 Spalten), LdapFieldMapping (6), TenderMatch (8), TenderSavedSearch (8) je neun Kennungen plus Relations-Kennung ldapconfig-systemkontext-include-fieldmappings-beider-mandanten -> Alle 253 Pruefungen bestanden - Detektor: FORSYSTEM_ALLOWED_CALL_SITES auf 4 Dateien / 5 Aufrufe; Proben-Empfaenger sysPrisma (Gate-Zaehlung, Name nicht hartkodiert) - Klassifikation: 6 Zeilen system-gebunden, settings/smtpConfig gebunden - Falsifizierung durch Rueckbau ausgefuehrt und zurueckgenommen: (a) FOR SELECT bei TenderMatch entfernt -> 5 von 253 rot (Insert gelingt, cmd ALL); (b) Regel TenderSavedSearch aus der Datei entfernt -> 1 von 245 rot (Extraktion), lebende DB bleibt bei 34; (c) local=false -> gruen, plus Reset entfernt -> 5 rot (Erben sichtbar); (d) Zahl 0 -> 2 rot, Fremddatei admin-seed -> 3 rot - Baseline: 64 Dateien / 1054 Tests, tsc 0, Werkzeug 253 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018N9CD3ebPKm1b32bPpBknY
This commit is contained in:
@@ -91,8 +91,10 @@ export class SettingsService {
|
||||
|
||||
/**
|
||||
* Internal: Get the decrypted SMTP config for a tenant.
|
||||
* Used by DkvMailService/TenderMailService to build a nodemailer transport
|
||||
* at send time — the ONLY send path (Befund K, 260909-laa/260909-mir).
|
||||
* Used by DkvMailService/TenderMailService — and seit 260914-eym auch von
|
||||
* MailService (Systemmails, Transport je Versand nach Mandant des
|
||||
* Empfaengers, WINDOWS #30) — to build a nodemailer transport at send
|
||||
* time — the ONLY send path (Befund K, 260909-laa/260909-mir).
|
||||
* NEVER log the decrypted password (T-07-10 / T-05-13).
|
||||
*
|
||||
* Mandantengebunden seit 260911-gwh (Aufgabe 2): EIN Klient
|
||||
@@ -190,75 +192,4 @@ export class SettingsService {
|
||||
return { success: false };
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tenant-agnostic startup accessor for the MailModule factory.
|
||||
*
|
||||
* BLEIBT bewusst UNGEBUNDEN (260911-gwh, sechster Fall der
|
||||
* Hintergrunddienst-Falle — gleicher Bauart wie
|
||||
* `DkvService.loadAnyActiveConfigForScheduler()`, WINDOWS #21, siehe
|
||||
* dessen Kopfkommentar als Vorlage). Zwei Zustaende, beide gehoeren
|
||||
* genannt:
|
||||
*
|
||||
* - HEUTE bereits falsch, nicht nur ungenau: `findFirst()` ohne jede
|
||||
* Bedingung zieht bei mehreren Mandanten den SMTP-Server und die
|
||||
* Absenderadresse EINES beliebigen Mandanten fuer ALLE
|
||||
* Kennwort-Zuruecksetzungs- und Willkommensmails ALLER Mandanten
|
||||
* (T-GWH-03 — Nutzung fremder Zugangsdaten, nicht nur Sichtbarkeit).
|
||||
* - NACH DEM SCHARFSCHALTEN (WINDOWS #18) liefert dieselbe Abfrage
|
||||
* `null`, `mail.module.ts` faellt auf Umgebungsvariablen und zuletzt
|
||||
* `localhost:1025` zurueck — ein FALSCHER, aber vorhandener Transport
|
||||
* statt einer Meldung; `MailService` faengt jeden Transportfehler
|
||||
* (T-02-12) und der Controller antwortet `200`. Das Verstummen ist
|
||||
* damit DOPPELT verdeckt: erst durch die Rueckfallkette, dann durch
|
||||
* das Verschlucken im Versand. Das ist die Unsymmetrie zu `ldap`
|
||||
* (`getAllActiveConfigs`, heute korrekt, verstummt erst spaeter) UND zu
|
||||
* `dkv` (WINDOWS #21, heute bereits falsch, verstummt spaeter MIT
|
||||
* Protokollzeile) — hier: heute bereits falsch, verstummt spaeter OHNE
|
||||
* Protokollzeile.
|
||||
*
|
||||
* Binden wuerde diesen Pfad garantiert leer laufen lassen (beim Start
|
||||
* gibt es strukturell keinen Mandantenkontext). Der Umbau auf Transport
|
||||
* je Versand aus `getDecryptedSmtpConfig(tenantId)` — die Form, die
|
||||
* `DkvMailService`/`TenderMailService` bereits haben, `MailService`
|
||||
* muesste den Mandanten nur von `requestPasswordReset` entgegennehmen —
|
||||
* ist eine Funktionsaenderung (Umbau des Mailmoduls), KEIN Bindungsumbau,
|
||||
* NICHT dieser Auftrag. Entscheidung: EIGENER Ledger-Eintrag statt
|
||||
* Anschluss an #21 (andere Datei, andere Reparatur, andere
|
||||
* Verdeckungsform) — siehe WINDOWS #30 und
|
||||
* `docs/mandantentrennung-etappe2-fehlerrichtung.md`, Abschnitt
|
||||
* "## Bereich settings", (s4)(a).
|
||||
*
|
||||
* D-06: MailModule reads this at startup (priority 1) and falls back to env vars (priority 2).
|
||||
* T-07-11: Decrypted password is used only to build the transport — never logged.
|
||||
*/
|
||||
async loadAnySmtpConfigForStartupTransport(): Promise<{
|
||||
host: string;
|
||||
port: number;
|
||||
secure: boolean;
|
||||
requireTLS: boolean;
|
||||
username: string | null;
|
||||
password: string | null;
|
||||
fromAddress: string;
|
||||
} | null> {
|
||||
const config = await this.prisma.smtpConfig.findFirst();
|
||||
|
||||
if (!config) return null;
|
||||
|
||||
let password: string | null = null;
|
||||
if (config.encryptedPassword) {
|
||||
// T-07-11: Used only to build transport at startup; never logged
|
||||
password = this.crypto.decrypt(config.encryptedPassword);
|
||||
}
|
||||
|
||||
return {
|
||||
host: config.host,
|
||||
port: config.port,
|
||||
secure: config.encryption === 'ssl-tls',
|
||||
requireTLS: config.encryption === 'starttls',
|
||||
username: config.username,
|
||||
password,
|
||||
fromAddress: config.fromAddress,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user