feat(security): share rate limits across instances, drain syncs on shutdown
- Rate limiting counters live in PostgreSQL (throttler_records), shared by every instance, one atomic upsert per request; fails open. - On shutdown, new syncs are refused (503) and the running one is waited for up to SYNC_SHUTDOWN_TIMEOUT; Prisma disconnects last. - Hiboutik calls never follow redirects and are capped at 50 MB. - Prisma errors no longer print query arguments (errorFormat minimal). - In production, DATABASE_URL must require TLS. - The sync lock connection times out after 10 s. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -12,6 +12,8 @@ import { ProductHiboutikRepository } from './hiboutik/product.hiboutik.repositor
|
||||
import { HttpModule } from '@nestjs/axios';
|
||||
import { CategoryDatabaseRepository } from './database/category.database.repository';
|
||||
import { PrismaModule } from '../prisma/prisma.module';
|
||||
import { PrismaService } from '../prisma/prisma.service';
|
||||
import { ThrottlerDatabaseStorage } from './database/throttlerStorage.database.repository';
|
||||
import { HiboutikClient } from './hiboutik/hiboutik.client';
|
||||
import { BrandHiboutikRepository } from './hiboutik/brand.hiboutik.repository';
|
||||
import { BrandDatabaseRepository } from './database/brand.database.repository';
|
||||
@@ -44,9 +46,22 @@ import { SyncLockDatabaseRepository } from './database/syncLock.database.reposit
|
||||
isGlobal: true,
|
||||
validate: validateEnv,
|
||||
}),
|
||||
// Default rate limit for every route: 60 requests per minute per IP (stricter limits via @Throttle)
|
||||
ThrottlerModule.forRoot([{ ttl: 60_000, limit: 60 }]),
|
||||
HttpModule.register({ timeout: 30_000 }),
|
||||
// Default rate limit for every route: 60 requests per minute per IP (stricter limits via @Throttle).
|
||||
// Counters live in PostgreSQL so that every instance shares them (see ThrottlerDatabaseStorage).
|
||||
ThrottlerModule.forRootAsync({
|
||||
inject: [PrismaService],
|
||||
useFactory: (prisma: PrismaService) => ({
|
||||
throttlers: [{ ttl: 60_000, limit: 60 }],
|
||||
storage: new ThrottlerDatabaseStorage(prisma),
|
||||
}),
|
||||
}),
|
||||
HttpModule.register({
|
||||
timeout: 30_000,
|
||||
// Hiboutik never redirects: never follow a redirect with the Basic auth credentials
|
||||
maxRedirects: 0,
|
||||
// A runaway answer (bug, faulty proxy) must not be loaded whole in memory
|
||||
maxContentLength: 50 * 1024 * 1024,
|
||||
}),
|
||||
PrismaModule,
|
||||
],
|
||||
controllers: [AppController],
|
||||
|
||||
Reference in New Issue
Block a user