import { DyFM_EnvironmentFlag, DyFM_Error } from '@futdevpro/fsm-dynamo'; import { DyNTS_global_settings } from './global-settings.const'; /** * Kliens-safe error-body SSOT (BFR-FDPAUTHSERVICE-002 — error-response info-disclosure fix). * * A DyFM_Error HTTP-response-ba szerializálásakor a belső diagnosztikai mezők NEM mehetnek ki a * kliensre — env-FÜGGETLENÜL (a korábbi prod-only strip a test/dev környezetben TELJES leaket * hagyott: `__localStack` stack-trace, `___systemVersion`, issuer-lánc). A strip-szabályok: * * 1. MINDIG ki (env-független, kliens sehol nem fogyasztja → 0 regresszió): * `__localStack`, `stack`, `___systemVersion`, `___issuer`, `___issuerSystem`, * `___issuerService`, `confidentialContent`, `error`, `errors` (a nyers belső error-lánc * stack-eket hordoz), `_messages` (QA2-005: technikai message-lánc — belső URL-ek, DB-hibák). * 2. CSAK prod-ban ki: `additionalContent` — test/dev környezetben a diagnosztikai state-snapshot * szándékosan kimegy (a hibafelület-debug erre épül), prod-ban nem. KIVÉTEL (QA2-005): * az `additionalContent.requestDebug` (FR-071 header-lista/belső-IP snapshot) env-FÜGGETLENÜL * strip-elve — csak az error-store-ba perzisztálódik. * 3. MARAD (kliens-kompatibilitás — a FDP-kliens error-interceptorok fogyasztják): * `_message`, `_errorCodes`, `__userMessage`, `___status`, `level`. QA2-005: a `_message` * TARTALMA a user-safe `__userMessage`-re cserélve (a technikai üzenet — belső BE-BE URL, * nyers Mongo E11000 — nem hagyhatja el a szervert; a mező-ALAK a kliens-kompat miatt marad). * * NEM-DyFM error (plain Error / axios-error / bármi más): minimál `{ message }` shape — a plain * Error eddig is üres `{}`-ként szerializálódott (non-enumerable mezők), az axios-jellegű error-ok * viszont enumerable config/request mezőkben auth-headert is szivárogtathatnak → fail-safe minimál. * * ⚠️ A metódus MUTÁLJA a kapott DyFM_Error-t (a meglévő endpoint-strip precedensét követve) — * a hívási pont a response-küldés, ahol az error-objektum életciklusa véget ér. */ export class DyNTS_ClientSafeError_Util { /** A MINDIG strip-elendő DyFM-mezők (env-független — kliens-fogyasztás nélküli leak-vektorok). */ private static readonly alwaysStripKeys: string[] = [ '__localStack', 'stack', '___systemVersion', '___issuer', '___issuerSystem', '___issuerService', 'confidentialContent', 'error', 'errors', // QA2-005 (dynamo-builder MP-23 QA-gate, 2026-07-18): a technikai message-LÁNC — belső BE-BE // URL-eket (pl. http://auth-service:39005/...), nyers DB-driver-hibákat (Mongo E11000) hordoz; // a kliens nem fogyasztja (a display-lánc `__userMessage` → `_message`), az error-store-ban marad. '_messages', ]; /** QA2-005 — generikus `_message` fallback, ha az errornak nincs `__userMessage`-e. */ private static readonly genericClientMessage: string = 'An internal error occurred.\nPlease contact the responsible development team.'; /** * Az error kliens-safe formára hozása a HTTP-response-küldés előtt. * DyFM_Error: in-place strip (1-3. szabályok szerint); nem-DyFM object: minimál `{ message }`. */ static toClientSafe(error: unknown): unknown { // DyFM_Error: célzott mező-strip, a kliens-fogyasztott mezők megtartásával if (DyFM_Error.isDyFMError(error)) { const dyError: Record = error as unknown as Record; for (const key of DyNTS_ClientSafeError_Util.alwaysStripKeys) { delete dyError[key]; } // ═══════════════════════════════════════════════════════════════════════ // QA2-005 — info-disclosure vágás env-FÜGGETLENÜL (test-env-ben SEM mehet ki): // a) `_message` (technikai üzenet): belső BE-BE URL-t / nyers Mongo-hibát hordozhat → // a response-ban a user-safe `__userMessage`-dzsel helyettesítjük. A mező ALAKJA // megmarad (a kliens-interceptorok / `DyFM_extractErrorMessage` fallback-lánca és a // `_message`-jelenlét-heurisztikák változatlanul működnek); a TELJES technikai üzenet // az error-store-ban marad (a globalErrorHandler a strip ELŐTT perzisztál). // b) `additionalContent.requestDebug` (FR-071 request-snapshot: header-kulcs-lista, // belső IP, params/query): csak az error-store-ba — a response-ból mindig kimarad; // az additionalContent TÖBBI (app-szintű diagnosztikai) mezője non-prod env-ben marad. // ═══════════════════════════════════════════════════════════════════════ const userMessage: unknown = dyError['__userMessage']; dyError['_message'] = (typeof userMessage === 'string' && userMessage) ? userMessage : DyNTS_ClientSafeError_Util.genericClientMessage; const additionalContent: unknown = dyError['additionalContent']; if (additionalContent && typeof additionalContent === 'object') { delete (additionalContent as Record)['requestDebug']; } // prod: a diagnosztikai state-snapshot sem megy ki; test/dev: szándékosan marad (debug-UX) if (DyNTS_global_settings.env_settings.environment === DyFM_EnvironmentFlag.prod) { delete dyError['additionalContent']; } return error; } // nem-DyFM object-error (plain/axios/egyéb): fail-safe minimál shape — a nyers objektum // enumerable mezői (pl. axios config.headers) szivárogtathatnak if (error && typeof error === 'object') { return { message: (error as Error).message ?? 'Internal server error' }; } return error; } }