refactor(quick-260921-m34): Aufgabe 3c - Randschicht beurteilt, drei Befunde gemeldet, 15 bleiben mit Urteil
httpntlm (exchange.provider, exchange-inbox.provider): NtlmOptions und
NtlmResponse beschreiben genau das, was uebergeben und gelesen wird. Die
ueberfluessige Zusicherung (httpntlm as any) faellt weg.
Graph-Rueckrufe (exchange.provider :157/:313): AuthProviderCallback aus dem
SDK selbst statt Handannotation - als import type, also ohne den dynamischen
Import zur Laufzeit zurueckzunehmen.
imapflow: streamToBuffer() nimmt Readable statt NodeJS.ReadableStream (alle
drei Aufrufer reichen client.download().content herein, imapflow deklariert
das als Readable) - damit traegt der Typ destroy() und die Zusicherung
faellt. node.parameters?.name war ebenfalls schon getypt.
nodemailer: ResolvedTransport.options wird SMTPTransport.Options; beide
Zweige bauen reine SMTP-Optionen, createTransport() nimmt sie ohne
Zusicherung.
node-forge: die vier let p7: any werden Captured<PkcsEnvelopedData |
PkcsSignedData> - der MITGELIEFERTE Typ. Die Lesestellen grenzen mit
'certificates' in p7 ein statt zuzusichern; verhaltensgleich, weil der
enveloped-Form das Feld fehlt und beide Schreibweisen dann die leere Liste
liefern. cert.siginfo war bereits getypt.
apps/web/src/test/setup.ts: expect.extend(matchers) traegt ohne Zusicherung
- geprueft im echten Typlauf (setup.ts liegt im include von
apps/web/tsconfig.json, mit einem absichtlichen Fehler nachgewiesen).
BEFUND 4 (D-03, gemeldet, NICHT repariert) imap.provider.ts:78 - der
Ausdruck (node as any).disposition?.parameters?.filename liest .parameters
von einer ZEICHENKETTE: imapflow deklariert disposition als string
(imap-flow.d.ts:448), die Parameter liegen in dispositionParameters (:450).
dispositionFilename ist damit zur Laufzeit immer ''. Folge: Outlook-Anhaenge,
die als application/octet-stream kommen, werden ueber den Dateinamen aus
Content-Disposition NICHT erkannt - nur ueber den aus Content-Type. Umbiegen
waere eine Verhaltensaenderung; die Zusicherung bleibt sichtbar stehen.
BEFUND 5 (D-03, gemeldet, NICHT repariert) imap.provider.ts:402 -
requireTLS kommt in imapflow 1.4.3 NIRGENDS vor, weder in ImapFlowOptions
noch im Laufzeitcode (beides durchsucht). Die Option wird still verworfen;
STARTTLS wird durch sie nicht erzwungen. Genau das } as any hat es
verdeckt. Bleibt stehen, damit der Befund in der Zaehlung sichtbar ist.
BEFUND 6 (D-03, gemeldet, Verhalten unveraendert) httpntlm liefert den
Rumpf als Zeichenkette, nicht als Buffer: httpreq setzt ihn nur bei
gesetzter Option binary auf Buffer (httpreq@1.1.1/lib/httpreq.js:391),
keiner der beiden Aufrufer setzt sie. Der Bestand rief unbesehen
.toString('utf-8') auf - das ging nur gut, weil String.toString() sein
Argument ignoriert. Die Testdoppel reichen dagegen wirklich Buffer herein.
NtlmResponse.body nennt jetzt beide Formen, die Fallunterscheidung liefert
fuer jede exakt dasselbe Ergebnis wie zuvor.
Urteil BLEIBT mit Begruendung im Code an allen 15 verbleibenden Stellen:
3x addCronJob (require-Umweg aus 07-04), 5x node-forge (EC-Zweig und
extensions: any[] sind in @types/node-forge nicht beschrieben, 2x null as
any wo die Typen die Bibliothek nachweislich falsch beschreiben), 2x
imap-Befunde oben, 2x tx: any plus 2x Gefolge (Aufgabe 1), 1x
disposition-Befund.
noExplicitAny in apps/api/src: 31 -> 15 (Ausgang 288, Schranke 45), apps/web
1 -> 0. type-check 4/4, lint 5/5 (0 error), apps/api 72/1143, apps/web
73/531, rls-access-inventory 30/30. noNonNullAssertion 56, as unknown as 33,
ts-expect-error/ts-ignore 0/0, Unterdrueckungsmarker 1. biome.json, alle
package.json und pnpm-lock.yaml unveraendert.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TPPB4ApQxzSU1rwV2Ffj9J
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import { Injectable, Logger } from '@nestjs/common';
|
||||
import type { Readable } from 'node:stream';
|
||||
import { ImapFlow, MessageStructureObject } from 'imapflow';
|
||||
import type { InboxAttachment, InboxConfig, InboxEmail, InboxMessage } from './inbox-provider.interface';
|
||||
import type { InboxProvider } from './inbox-provider.interface';
|
||||
@@ -14,9 +15,7 @@ const MAX_ATTACHMENT_BYTES = 25 * 1024 * 1024; // 25 MB
|
||||
* Converts a Node.js Readable stream into a Buffer.
|
||||
* Accumulates chunks up to MAX_ATTACHMENT_BYTES; throws if limit exceeded.
|
||||
*/
|
||||
async function streamToBuffer(
|
||||
stream: NodeJS.ReadableStream,
|
||||
): Promise<Buffer> {
|
||||
async function streamToBuffer(stream: Readable): Promise<Buffer> {
|
||||
return new Promise<Buffer>((resolve, reject) => {
|
||||
const chunks: Buffer[] = [];
|
||||
let total = 0;
|
||||
@@ -24,8 +23,12 @@ async function streamToBuffer(
|
||||
stream.on('data', (chunk: Buffer) => {
|
||||
total += chunk.length;
|
||||
if (total > MAX_ATTACHMENT_BYTES) {
|
||||
// Destroy the stream to prevent further data emission
|
||||
(stream as any).destroy?.();
|
||||
// Destroy the stream to prevent further data emission.
|
||||
// Readable statt NodeJS.ReadableStream: alle drei Aufrufer reichen
|
||||
// client.download().content herein, und imapflow deklariert das als
|
||||
// Readable (imap-flow.d.ts:521). Readable traegt destroy(), also
|
||||
// braucht der Aufruf keine Zusicherung mehr.
|
||||
stream.destroy?.();
|
||||
reject(
|
||||
new Error(
|
||||
`Attachment exceeds maximum allowed size of ${MAX_ATTACHMENT_BYTES} bytes (T-07-05)`,
|
||||
@@ -59,10 +62,23 @@ function collectPdfParts(
|
||||
const type = node.type?.toLowerCase() ?? '';
|
||||
// Some mail clients (e.g. Outlook) send PDFs as application/octet-stream.
|
||||
// Fall back to checking the filename from Content-Disposition or Content-Type parameters.
|
||||
// BLEIBT als any, mit Befund (260921-m34, Aufgabe 3c, D-01/D-03):
|
||||
// imapflow deklariert `disposition` als ZEICHENKETTE (imap-flow.d.ts:448,
|
||||
// also "attachment"/"inline"), und die zugehoerigen Parameter liegen in
|
||||
// einem eigenen Feld `dispositionParameters` (:450). Der Ausdruck unten
|
||||
// liest `.parameters` von einer Zeichenkette und ist damit zur Laufzeit
|
||||
// IMMER undefined — dispositionFilename ist stets ''. Das ist ein Befund
|
||||
// im Bestandscode, kein Typproblem: ihn hier auf `dispositionParameters`
|
||||
// umzubiegen waere eine Verhaltensaenderung (Outlook-Anhaenge als
|
||||
// application/octet-stream wuerden ab dann erstmals erkannt), und die ist
|
||||
// in dieser Aufgabe verboten. Gemeldet im SUMMARY, Entscheidung beim
|
||||
// Menschen. Die Zusicherung bleibt sichtbar stehen, damit der Befund
|
||||
// nicht verschwindet.
|
||||
const dispositionFilename =
|
||||
((node as any).disposition?.parameters?.filename as string | undefined)?.toLowerCase() ?? '';
|
||||
const typeFilename =
|
||||
((node as any).parameters?.name as string | undefined)?.toLowerCase() ?? '';
|
||||
// Hier dagegen war die Zusicherung schlicht ueberfluessig: imapflow
|
||||
// deklariert `parameters?: { [key: string]: string }` (imap-flow.d.ts:438).
|
||||
const typeFilename = node.parameters?.name?.toLowerCase() ?? '';
|
||||
const looksLikePdf =
|
||||
type === 'application/pdf' ||
|
||||
(type === 'application/octet-stream' &&
|
||||
@@ -374,6 +390,15 @@ export class ImapProvider implements InboxProvider {
|
||||
: undefined,
|
||||
// T-07-03: suppress imapflow verbose logs — they include auth credentials
|
||||
logger: false,
|
||||
// BLEIBT als Zusicherung, mit Befund (260921-m34, Aufgabe 3c, D-03):
|
||||
// `requireTLS` oben kommt in imapflow 1.4.3 NIRGENDS vor — weder in
|
||||
// ImapFlowOptions (lib/imap-flow.d.ts) noch im Laufzeitcode
|
||||
// (lib/imap-flow.js), beides durchsucht. Die Option wird also still
|
||||
// verworfen; STARTTLS wird nicht durch sie erzwungen. Genau diese
|
||||
// Zusicherung hat das bisher verdeckt. Sie bleibt trotzdem stehen:
|
||||
// die Option zu entfernen waere eine stille Reparatur einer falschen
|
||||
// Annahme (verboten), und der `any`-Befund haelt die Stelle in der
|
||||
// Zaehlung sichtbar, bis ein Mensch entscheidet. Gemeldet im SUMMARY.
|
||||
} as any);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user