Files
ApiCore/ApiCore-Backend/src/main.ts
T
Nick SzaunigandClaude Sonnet 5 33fa768062
Backend Image / build-and-push (push) Successful in 2m13s
Frontend Image / build-and-push (push) Successful in 1m59s
fix: Mindestlaenge fuer JWT_ACCESS_SECRET beim Start erzwungen
JWT_ACCESS_SECRET war zwar als Pflicht-Env-Var geprueft, aber ohne
Mindestlaenge - ein kurzer/erratbarer Wert haette nicht nur das
Faelschen von Access-/MFA-/SSO-Tokens fuer jeden Nutzer erlaubt,
sondern auch (ueber mfa-crypto.util.ts, das den AES-Schluessel fuer
gespeicherte TOTP-Secrets aus genau diesem Wert ableitet) das
Entschluesseln aller gespeicherten MFA-Secrets.

main.ts bricht den Start jetzt mit klarer Fehlermeldung ab, wenn
JWT_ACCESS_SECRET kuerzer als 32 Zeichen ist. .env.example und das
K8s-Secret-Template zeigen jetzt einen ausreichend langen Platzhalter
mit Erzeugungshinweis (openssl rand -hex 32).

Betrifft nur main.ts's bootstrap() - e2e-Tests bootstrappen ueber
test/utils/create-test-app.ts direkt via configureApp() und durchlaufen
diese Pruefung nicht, daher keine Testanpassung noetig.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
2026-09-02 15:17:39 +02:00

60 lines
2.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { NestFactory } from '@nestjs/core';
import { NestExpressApplication } from '@nestjs/platform-express';
import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
import { AppModule } from './app.module';
import { configureApp } from './app.config';
const REQUIRED_ENV_VARS = ['DATABASE_URL', 'JWT_ACCESS_SECRET'] as const;
// JWT_ACCESS_SECRET is the root of trust for both authentication (every
// access/MFA-challenge/SSO-completion token is signed with it) and MFA
// secret confidentiality (mfa-crypto.util.ts derives the AES key that
// encrypts stored TOTP secrets from it) - a short or guessable value here
// would let an attacker forge tokens for any user AND decrypt everyone's
// stored TOTP secret, not just guess a password. 32 chars matches the
// output of "openssl rand -hex 32" / "-base64 32", the standard way to
// generate one.
const MIN_JWT_SECRET_LENGTH = 32;
function assertRequiredEnvVars(): void {
const missing = REQUIRED_ENV_VARS.filter((name) => !process.env[name]);
if (missing.length > 0) {
throw new Error(
`Missing required environment variable(s): ${missing.join(', ')}`,
);
}
const jwtSecret = process.env.JWT_ACCESS_SECRET as string;
if (jwtSecret.length < MIN_JWT_SECRET_LENGTH) {
throw new Error(
`JWT_ACCESS_SECRET must be at least ${MIN_JWT_SECRET_LENGTH} characters (got ${jwtSecret.length}) - generate one with e.g. "openssl rand -hex 32"`,
);
}
}
async function bootstrap() {
assertRequiredEnvVars();
const app = await NestFactory.create<NestExpressApplication>(AppModule);
app.enableShutdownHooks();
configureApp(app);
// Swagger is mounted as raw Express middleware outside Nest's routing, so
// it is never covered by the global JwtAuthGuard - anyone reaching the
// host could otherwise read the full API schema (every endpoint and DTO
// shape) with no authentication at all. Off by default; an operator who
// wants it in a given environment opts in explicitly.
if (process.env.ENABLE_SWAGGER === 'true') {
const swaggerConfig = new DocumentBuilder()
.setTitle('ApiCore API')
.setDescription('Digitale Imkereiverwaltung – API-Dokumentation')
.setVersion('1.0')
.addBearerAuth()
.build();
const swaggerDocument = SwaggerModule.createDocument(app, swaggerConfig);
SwaggerModule.setup('api/v1/docs', app, swaggerDocument);
}
await app.listen(process.env.PORT ?? 3001);
}
void bootstrap();