Files
opencrm/backend/scripts/check-portal-password-sync.ts
duffyduckandClaude Opus 4.8 79f6f3e629 Portal-Passwort: Reveal/Send prueft Konsistenz gegen Login-Hash
Pentester-Hinweis: bcrypt-Hash (Login) und verschluesseltes Reveal-Feld
koennen out-of-sync sein -> Support liest ein Passwort vor, das beim
Login scheitert.

Analyse: alle aktuellen Schreibpfade sind konsistent (beide Felder
zusammen, oder encrypted=null, oder Rehash desselben Passworts) - der
Code erzeugt keinen Desync. Ursache = Altlast/manueller DB-Eingriff.

Fix (defensiv, unabhaengig von der Ursache):
- getCustomerPortalPassword liefert {status: ok|none|desync} und prueft
  den entschluesselten Klartext per bcrypt.compare gegen den Login-Hash.
- Bei desync (oder Entschluesselungsfehler) geben WEDER Reveal NOCH
  Send-Credentials das Passwort aus -> 409 'Dateninkonsistenz, bitte
  neu setzen'. Reveal-Read wird mit Status auditiert.
- Neues Diagnose-Script scripts/check-portal-password-sync.ts scannt
  alle Portal-Kunden auf Desync (nur Diagnose, aendert nichts) - fuer
  Prod, da der Pentester keinen FS-Zugriff hat.

Verifiziert: desync -> nicht ausgegeben; konsistent -> ok; kein PW ->
none. Scan laeuft (0 Desync auf Dev).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-08-11 22:46:53 +02:00

62 lines
2.0 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* Diagnose: findet Portal-Kunden, deren gespeichertes (verschlüsseltes)
* Passwort NICHT zum Login-Hash (bcrypt) passt. Solche „Desyncs" führen dazu,
* dass der Reveal/Send-Credentials ein Passwort ausgibt, das beim Login
* scheitert. Seit dem Reveal-Konsistenzcheck werden sie nicht mehr ausgegeben
* dieses Script findet bestehende Altlasten (z.B. aus manuellen DB-Eingriffen
* oder alten Code-Versionen), damit man sie gezielt neu setzen kann.
*
* Aufruf (im Backend-Container/-Verzeichnis):
* npx tsx scripts/check-portal-password-sync.ts
* Nur Diagnose ändert NICHTS.
*/
import { PrismaClient } from '@prisma/client';
import bcrypt from 'bcryptjs';
import { decrypt } from '../src/utils/encryption.js';
const prisma = new PrismaClient();
async function main() {
const customers = await prisma.customer.findMany({
where: { portalPasswordEncrypted: { not: null }, portalPasswordHash: { not: null } },
select: {
id: true,
customerNumber: true,
portalEmail: true,
portalPasswordEncrypted: true,
portalPasswordHash: true,
},
});
let desync = 0;
for (const c of customers) {
let decrypted: string;
try {
decrypted = decrypt(c.portalPasswordEncrypted!);
} catch {
desync++;
console.log(`DESYNC (Entschlüsselung fehlgeschlagen): Kunde #${c.id} ${c.customerNumber}`);
continue;
}
const matches = await bcrypt.compare(decrypted, c.portalPasswordHash!);
if (!matches) {
desync++;
console.log(`DESYNC: Kunde #${c.id} ${c.customerNumber} (${c.portalEmail ?? '-'}) gespeichertes Passwort passt nicht zum Login-Hash`);
}
}
console.log(`\nGeprüft: ${customers.length} Portal-Kunden mit beiden Feldern. Desync: ${desync}.`);
if (desync > 0) {
console.log('→ Für diese Kunden bitte ein neues Portal-Passwort setzen/generieren.');
} else {
console.log('→ Alles konsistent.');
}
await prisma.$disconnect();
}
main().catch((e) => {
console.error(e);
process.exit(1);
});