Spam-Tab: Anhänge aus dem echten Junk-Ordner holen (Pentest R124)
Beim Spam-Feature wurden moveEmailToTrash/restoreEmailFromTrash auf den echten Junk-Pfad umgestellt, vier Attachment-Funktionen im Controller aber nicht: downloadAttachment, saveAttachmentTo, saveAttachmentAsInvoice, saveAttachmentAsContractDocument bestimmten den IMAP-Ordner weiter hart als email.folder === 'SENT' ? 'Sent' : 'INBOX'. Für SPAM-Mails landete das fälschlich auf INBOX. Da IMAP-UIDs pro Ordner vergeben sind: bestenfalls 404, schlimmstenfalls (UID-Kollision INBOX vs. Junk) der FALSCHE Anhang aus INBOX – der dann z.B. als Rechnung/Vertragsdokument abgelegt würde. Kein Cross-Customer-Leak (gleicher Kunde/Postfach), aber Datenintegritätsproblem. Fix: an allen vier Stellen dieselbe Junk-Pfad-Logik wie in moveEmailToTrash (email.folder === 'SPAM' → findJunkFolderPath). findJunkFolderPath war in dem Controller noch nicht importiert. Vom Pentester (R124) gefunden – beim ursprünglichen Feature übersehen. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -5,7 +5,7 @@ import * as cachedEmailService from '../services/cachedEmail.service.js';
|
||||
import * as stressfreiEmailService from '../services/stressfreiEmail.service.js';
|
||||
import * as invoiceService from '../services/invoice.service.js';
|
||||
import { sendEmail, SmtpCredentials, SendEmailParams, EmailAttachment } from '../services/smtpService.js';
|
||||
import { fetchAttachment, appendToSent, ImapCredentials, humanizeImapError } from '../services/imapService.js';
|
||||
import { fetchAttachment, appendToSent, ImapCredentials, humanizeImapError, findJunkFolderPath } from '../services/imapService.js';
|
||||
import { getImapSmtpSettings } from '../services/emailProvider/emailProviderService.js';
|
||||
import { decrypt } from '../utils/encryption.js';
|
||||
import { sanitizeNotes, stripHtml, validateContractDocumentType, validateOptionalIsoDate, assertSafePdf } from '../utils/sanitize.js';
|
||||
@@ -740,7 +740,19 @@ export async function downloadAttachment(req: AuthRequest, res: Response): Promi
|
||||
};
|
||||
|
||||
// Ordner basierend auf E-Mail-Typ bestimmen (INBOX oder Sent)
|
||||
const imapFolder = email.folder === 'SENT' ? 'Sent' : 'INBOX';
|
||||
// SPAM-Mails liegen im Junk-Ordner (Name variiert je Server) – IMAP-UIDs
|
||||
// sind pro Ordner vergeben, daher MUSS der echte Junk-Pfad ermittelt
|
||||
// werden, sonst wird der Anhang im falschen Ordner gesucht (404 oder,
|
||||
// bei UID-Kollision, der falsche Anhang aus INBOX). Gleiches Muster wie
|
||||
// cachedEmail.service.ts::moveEmailToTrash.
|
||||
let imapFolder: string;
|
||||
if (email.folder === 'SENT') {
|
||||
imapFolder = 'Sent';
|
||||
} else if (email.folder === 'SPAM') {
|
||||
imapFolder = (await findJunkFolderPath(credentials)) || 'Junk';
|
||||
} else {
|
||||
imapFolder = 'INBOX';
|
||||
}
|
||||
|
||||
// Anhang per IMAP abrufen
|
||||
const attachment = await fetchAttachment(credentials, email.uid, filename, imapFolder);
|
||||
@@ -1405,7 +1417,19 @@ export async function saveAttachmentTo(req: AuthRequest, res: Response): Promise
|
||||
};
|
||||
|
||||
// Ordner basierend auf E-Mail-Typ bestimmen (INBOX oder Sent)
|
||||
const imapFolder = email.folder === 'SENT' ? 'Sent' : 'INBOX';
|
||||
// SPAM-Mails liegen im Junk-Ordner (Name variiert je Server) – IMAP-UIDs
|
||||
// sind pro Ordner vergeben, daher MUSS der echte Junk-Pfad ermittelt
|
||||
// werden, sonst wird der Anhang im falschen Ordner gesucht (404 oder,
|
||||
// bei UID-Kollision, der falsche Anhang aus INBOX). Gleiches Muster wie
|
||||
// cachedEmail.service.ts::moveEmailToTrash.
|
||||
let imapFolder: string;
|
||||
if (email.folder === 'SENT') {
|
||||
imapFolder = 'Sent';
|
||||
} else if (email.folder === 'SPAM') {
|
||||
imapFolder = (await findJunkFolderPath(credentials)) || 'Junk';
|
||||
} else {
|
||||
imapFolder = 'INBOX';
|
||||
}
|
||||
|
||||
// Anhang per IMAP abrufen
|
||||
const attachment = await fetchAttachment(credentials, email.uid, filename, imapFolder);
|
||||
@@ -2211,7 +2235,19 @@ export async function saveAttachmentAsInvoice(req: AuthRequest, res: Response):
|
||||
};
|
||||
|
||||
// IMAP-Ordner bestimmen
|
||||
const imapFolder = email.folder === 'SENT' ? 'Sent' : 'INBOX';
|
||||
// SPAM-Mails liegen im Junk-Ordner (Name variiert je Server) – IMAP-UIDs
|
||||
// sind pro Ordner vergeben, daher MUSS der echte Junk-Pfad ermittelt
|
||||
// werden, sonst wird der Anhang im falschen Ordner gesucht (404 oder,
|
||||
// bei UID-Kollision, der falsche Anhang aus INBOX). Gleiches Muster wie
|
||||
// cachedEmail.service.ts::moveEmailToTrash.
|
||||
let imapFolder: string;
|
||||
if (email.folder === 'SENT') {
|
||||
imapFolder = 'Sent';
|
||||
} else if (email.folder === 'SPAM') {
|
||||
imapFolder = (await findJunkFolderPath(credentials)) || 'Junk';
|
||||
} else {
|
||||
imapFolder = 'INBOX';
|
||||
}
|
||||
|
||||
// Anhang vom IMAP-Server laden
|
||||
const attachment = await fetchAttachment(credentials, email.uid, filename, imapFolder);
|
||||
@@ -2370,7 +2406,19 @@ export async function saveAttachmentAsContractDocument(req: AuthRequest, res: Re
|
||||
allowSelfSignedCerts: settings.allowSelfSignedCerts,
|
||||
};
|
||||
|
||||
const imapFolder = email.folder === 'SENT' ? 'Sent' : 'INBOX';
|
||||
// SPAM-Mails liegen im Junk-Ordner (Name variiert je Server) – IMAP-UIDs
|
||||
// sind pro Ordner vergeben, daher MUSS der echte Junk-Pfad ermittelt
|
||||
// werden, sonst wird der Anhang im falschen Ordner gesucht (404 oder,
|
||||
// bei UID-Kollision, der falsche Anhang aus INBOX). Gleiches Muster wie
|
||||
// cachedEmail.service.ts::moveEmailToTrash.
|
||||
let imapFolder: string;
|
||||
if (email.folder === 'SENT') {
|
||||
imapFolder = 'Sent';
|
||||
} else if (email.folder === 'SPAM') {
|
||||
imapFolder = (await findJunkFolderPath(credentials)) || 'Junk';
|
||||
} else {
|
||||
imapFolder = 'INBOX';
|
||||
}
|
||||
|
||||
const attachment = await fetchAttachment(credentials, email.uid, filename, imapFolder);
|
||||
if (!attachment) {
|
||||
|
||||
@@ -97,6 +97,21 @@ isolierte Instanz (keine Multi-Tenancy im Code), Provisioning + Abrechnung
|
||||
|
||||
## ✅ Erledigt
|
||||
|
||||
- [x] **🐞 Spam-Tab: Anhänge aus Junk-Ordner (Pentest R124-Fund)**
|
||||
- Beim Spam-Feature wurden `moveEmailToTrash`/`restoreEmailFromTrash`
|
||||
auf den echten Junk-Pfad umgestellt, aber vier Attachment-Funktionen
|
||||
im Controller (`downloadAttachment`, `saveAttachmentTo`,
|
||||
`saveAttachmentAsInvoice`, `saveAttachmentAsContractDocument`)
|
||||
bestimmten den IMAP-Ordner weiter hart als
|
||||
`email.folder === 'SENT' ? 'Sent' : 'INBOX'`. Für SPAM-Mails landete
|
||||
das fälschlich auf INBOX. Da IMAP-UIDs pro Ordner vergeben sind:
|
||||
404 (Anhang nicht gefunden) oder – bei UID-Kollision – der falsche
|
||||
Anhang aus INBOX (z.B. als Rechnung/Vertragsdokument abgelegt).
|
||||
Kein Cross-Customer-Leak (bleibt im selben Postfach), aber echtes
|
||||
Datenintegritätsproblem.
|
||||
- Fix: an allen vier Stellen dieselbe Junk-Pfad-Logik wie in
|
||||
`moveEmailToTrash` + `findJunkFolderPath` importiert.
|
||||
|
||||
- [x] **📧 E-Mail-Client: Spam-Ordner als eigener Tab**
|
||||
- Neuer Tab „Spam" (zwischen Gesendet und Papierkorb) im E-Mail-Client,
|
||||
zeigt den Junk-/Spam-Ordner des gewählten Postfachs – damit
|
||||
|
||||
Reference in New Issue
Block a user