55 lines
1.6 KiB
TypeScript
55 lines
1.6 KiB
TypeScript
import { ValidationPipe } from '@nestjs/common';
|
|
import { NestFactory } from '@nestjs/core';
|
|
import { AppModule } from './app.module';
|
|
import { GlobalExceptionFilter } from './common/filters/global-exception.filter';
|
|
import helmet from 'helmet';
|
|
|
|
async function bootstrap() {
|
|
const app = await NestFactory.create(AppModule);
|
|
|
|
// CORS — tillåt endast appens egen origin (sätts via ALLOWED_ORIGIN i miljövariabler)
|
|
const allowedOrigin = process.env.ALLOWED_ORIGIN || 'https://recept.gynther.se';
|
|
app.enableCors({
|
|
origin: allowedOrigin,
|
|
methods: ['GET', 'POST', 'PATCH', 'PUT', 'DELETE', 'OPTIONS'],
|
|
allowedHeaders: ['Content-Type', 'Authorization'],
|
|
credentials: true,
|
|
});
|
|
|
|
// Helmet som säkerhetsbackup (CSP hanteras av Next.js/Caddy)
|
|
app.use(
|
|
helmet({
|
|
contentSecurityPolicy: false,
|
|
crossOriginEmbedderPolicy: true,
|
|
crossOriginOpenerPolicy: { policy: 'same-origin' },
|
|
crossOriginResourcePolicy: { policy: 'same-origin' },
|
|
originAgentCluster: true,
|
|
referrerPolicy: { policy: 'strict-origin-when-cross-origin' },
|
|
strictTransportSecurity: {
|
|
maxAge: 31536000,
|
|
includeSubDomains: true,
|
|
preload: true,
|
|
},
|
|
xContentTypeOptions: true,
|
|
xFrameOptions: { action: 'deny' },
|
|
xXssProtection: false, // Deprecated, hanteras av Caddy
|
|
}),
|
|
);
|
|
|
|
app.setGlobalPrefix('api');
|
|
|
|
// Registrera global exception filter
|
|
app.useGlobalFilters(new GlobalExceptionFilter());
|
|
|
|
app.useGlobalPipes(
|
|
new ValidationPipe({
|
|
whitelist: true,
|
|
forbidNonWhitelisted: true,
|
|
transform: true,
|
|
}),
|
|
);
|
|
|
|
await app.listen(8080, '0.0.0.0');
|
|
}
|
|
bootstrap();
|