Add HTTP security headers and CORS defaults

This commit is contained in:
Tor Matz Andrén
2026-05-14 16:38:42 +02:00
parent 41f5a80ffb
commit f9e4cf5d07
6 changed files with 49 additions and 2 deletions
+10 -1
View File
@@ -14,7 +14,8 @@
"dependencies": { "dependencies": {
"@nestjs/throttler": "^6.5.0", "@nestjs/throttler": "^6.5.0",
"class-transformer": "^0.5.1", "class-transformer": "^0.5.1",
"class-validator": "^0.15.1" "class-validator": "^0.15.1",
"helmet": "^8.1.0"
}, },
"devDependencies": { "devDependencies": {
"@release-it/bumper": "^7.0.1", "@release-it/bumper": "^7.0.1",
@@ -14434,6 +14435,14 @@
"node": ">= 0.4" "node": ">= 0.4"
} }
}, },
"node_modules/helmet": {
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/helmet/-/helmet-8.1.0.tgz",
"integrity": "sha512-jOiHyAZsmnr8LqoPGmCjYAaiuWwjAPLgY8ZX2XrmHawt99/u1y6RgrZMTeoPfpUbV96HOalYgz1qzkRbw54Pmg==",
"engines": {
"node": ">=18.0.0"
}
},
"node_modules/himalaya": { "node_modules/himalaya": {
"version": "1.1.1", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/himalaya/-/himalaya-1.1.1.tgz", "resolved": "https://registry.npmjs.org/himalaya/-/himalaya-1.1.1.tgz",
+2 -1
View File
@@ -34,6 +34,7 @@
"dependencies": { "dependencies": {
"@nestjs/throttler": "^6.5.0", "@nestjs/throttler": "^6.5.0",
"class-transformer": "^0.5.1", "class-transformer": "^0.5.1",
"class-validator": "^0.15.1" "class-validator": "^0.15.1",
"helmet": "^8.1.0"
} }
} }
+6
View File
@@ -19,3 +19,9 @@ YT_DOWNLOADS_PER_MINUTE=3
# Optional local hardening. Set AUTH_ENABLED=true and choose a strong token. # Optional local hardening. Set AUTH_ENABLED=true and choose a strong token.
AUTH_ENABLED=false AUTH_ENABLED=false
SPOOTY_AUTH_TOKEN= SPOOTY_AUTH_TOKEN=
# Optional frontend origin restriction
CORS_ORIGIN=http://localhost:4200
NODE_ENV=development
+6
View File
@@ -17,3 +17,9 @@ YT_DOWNLOADS_PER_MINUTE=3
# Optional local hardening. Set AUTH_ENABLED=true and choose a strong token. # Optional local hardening. Set AUTH_ENABLED=true and choose a strong token.
AUTH_ENABLED=false AUTH_ENABLED=false
SPOOTY_AUTH_TOKEN= SPOOTY_AUTH_TOKEN=
# Optional frontend origin restriction
CORS_ORIGIN=http://localhost:4200
NODE_ENV=production
+2
View File
@@ -10,4 +10,6 @@ export enum EnvironmentEnum {
YT_COOKIES_FILE = 'YT_COOKIES_FILE', YT_COOKIES_FILE = 'YT_COOKIES_FILE',
AUTH_ENABLED = 'AUTH_ENABLED', AUTH_ENABLED = 'AUTH_ENABLED',
SPOOTY_AUTH_TOKEN = 'SPOOTY_AUTH_TOKEN', SPOOTY_AUTH_TOKEN = 'SPOOTY_AUTH_TOKEN',
CORS_ORIGIN = 'CORS_ORIGIN',
NODE_ENV = 'NODE_ENV',
} }
+23
View File
@@ -5,6 +5,7 @@ import { AppModule } from './app.module';
import * as fs from 'fs'; import * as fs from 'fs';
import { resolve } from 'path'; import { resolve } from 'path';
import { exec } from 'child_process'; import { exec } from 'child_process';
import helmet from 'helmet';
import { EnvironmentEnum } from './environmentEnum'; import { EnvironmentEnum } from './environmentEnum';
function envFlag(name: string): boolean { function envFlag(name: string): boolean {
@@ -46,6 +47,28 @@ async function bootstrap() {
); );
app.useGlobalFilters(new HttpExceptionFilter()); app.useGlobalFilters(new HttpExceptionFilter());
app.use(
helmet({
crossOriginResourcePolicy: false,
}),
);
const corsOrigin =
process.env[EnvironmentEnum.CORS_ORIGIN] || 'http://localhost:4200';
app.enableCors({
origin: corsOrigin,
credentials: false,
});
if (
process.env[EnvironmentEnum.NODE_ENV] === 'production' &&
!envFlag(EnvironmentEnum.AUTH_ENABLED)
) {
console.warn('[SECURITY] AUTH_ENABLED is false while NODE_ENV=production');
}
app.setGlobalPrefix('api'); app.setGlobalPrefix('api');
await app.listen(process.env.PORT || 3000); await app.listen(process.env.PORT || 3000);
} }