import { createHash } from "node:crypto"; import { Logger, ValidationPipe } from "@nestjs/common"; import { ConfigService } from "@nestjs/config"; import { NestFactory } from "@nestjs/core"; import { NestExpressApplication } from "@nestjs/platform-express"; import * as Sentry from "@sentry/nestjs"; import { nodeProfilingIntegration } from "@sentry/profiling-node"; import helmet from "helmet"; import { AppModule } from "./app.module"; import { AllExceptionsFilter } from "./common/filters/http-exception.filter"; async function bootstrap() { const app = await NestFactory.create(AppModule); const configService = app.get(ConfigService); const logger = new Logger("Bootstrap"); // Activer trust proxy pour récupérer l'IP réelle derrière un reverse proxy app.set("trust proxy", true); const sentryDsn = configService.get("SENTRY_DSN"); if (sentryDsn) { try { Sentry.init({ dsn: sentryDsn, integrations: [Sentry.nestIntegration(), nodeProfilingIntegration()], tracesSampleRate: 1.0, profilesSampleRate: 1.0, sendDefaultPii: false, // RGPD beforeSend(event) { // Hachage de l'IP utilisateur pour Sentry si elle est présente if (event.user?.ip_address) { event.user.ip_address = createHash("sha256") .update(event.user.ip_address) .digest("hex"); } return event; }, }); const client = Sentry.getClient(); if (client?.getOptions().dsn) { logger.log("Sentry is initialized and connection is active"); } else { logger.warn("Sentry initialized but DSN is missing"); } } catch (error) { logger.error(`Failed to initialize Sentry: ${error.message}`); } } else { logger.warn("Sentry is disabled (SENTRY_DSN not configured)"); } // Sécurité app.use( helmet({ crossOriginResourcePolicy: { policy: "cross-origin" }, }), ); const corsEnabled = Boolean(configService.get("ENABLE_CORS")); if (corsEnabled) { const domainName = configService.get("CORS_DOMAIN_NAME"); app.enableCors({ origin: (origin, callback) => { if (!origin || domainName === "*") { callback(null, true); return; } const allowedOrigins = domainName?.split(",").map((o) => o.trim()) || []; if (allowedOrigins.includes(origin)) { callback(null, true); } else { callback(null, false); } }, credentials: true, }); } // Validation Globale app.useGlobalPipes( new ValidationPipe({ whitelist: true, forbidNonWhitelisted: true, transform: true, }), ); // Filtre d'exceptions global app.useGlobalFilters(new AllExceptionsFilter()); const port = configService.get("PORT") || 3000; await app.listen(port); logger.log(`Application is running on: http://localhost:${port}`); } bootstrap().then();