Verify ALTCHA before upload body parse with single-use replay store.

Run challenge TTL and replay tracking in middleware, remove the guard, and
wire ScheduleModule for pruning used solutions.
This commit is contained in:
2026-10-12 20:18:36 +02:00
parent 96383a7426
commit 7f99256863
15 changed files with 446 additions and 84 deletions
+36 -5
View File
@@ -1,17 +1,48 @@
import { ValidationPipe } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { NestFactory } from '@nestjs/core';
import { NestExpressApplication } from '@nestjs/platform-express';
import express, { type NextFunction, type Request, type Response } from 'express';
import { AppModule } from './AppModule';
import { Config } from './types/Config';
import { altchaMiddleware } from './middlewares/altchaMiddleware';
import { AltchaService } from './modules/altcha/services/AltchaService';
import { Config } from './types/config/Config';
import { HttpMethod } from './types/HttpMethod';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
const configService = app.get(ConfigService);
const { port, corsOrigins } = configService.get('app') as Config['app'];
const app = await NestFactory.create<NestExpressApplication>(AppModule, { bodyParser: false });
app.setGlobalPrefix('api');
const configService = app.get(ConfigService);
const altchaService = app.get(AltchaService);
const {
port,
corsOrigins,
validation: {
upload: { maxRequestBodyBytes }
}
} = configService.get('app') as Config['app'];
const defaultJsonParser = express.json();
const uploadJsonParser = express.json({ limit: maxRequestBodyBytes });
const uploadAltchaMiddleware = altchaMiddleware(altchaService);
app.use((req: Request, res: Response, next: NextFunction) => {
if (req.method === HttpMethod.Post && req.path.startsWith('/api/uploads')) {
return uploadAltchaMiddleware(req, res, (err: unknown) => {
if (err) {
return next(err);
}
return uploadJsonParser(req, res, next);
});
}
return defaultJsonParser(req, res, next);
});
app.useGlobalPipes(
new ValidationPipe({
transform: true,