Slave/altcha throttle #4

Merged
nobswebdev merged 6 commits from slave/altcha-throttle into master 2026-10-06 17:55:47 +00:00
8 changed files with 77 additions and 25 deletions
Showing only changes of commit 7e4a889b50 - Show all commits
+15
View File
@@ -13,6 +13,7 @@
"@nestjs/config": "^4.0.3", "@nestjs/config": "^4.0.3",
"@nestjs/core": "^11.0.1", "@nestjs/core": "^11.0.1",
"@nestjs/platform-express": "^11.0.1", "@nestjs/platform-express": "^11.0.1",
"@nestjs/throttler": "^6.7.1",
"@nestjs/typeorm": "^12.0.2", "@nestjs/typeorm": "^12.0.2",
"altcha-lib": "^2.6.0", "altcha-lib": "^2.6.0",
"class-transformer": "^0.5.1", "class-transformer": "^0.5.1",
@@ -1995,6 +1996,20 @@
"tslib": "^2.1.0" "tslib": "^2.1.0"
} }
}, },
"node_modules/@nestjs/throttler": {
"version": "6.7.1",
"resolved": "https://registry.npmjs.org/@nestjs/throttler/-/throttler-6.7.1.tgz",
"integrity": "sha512-gAyY1AkU+cSK5DCjFOB43xax9oakameH4xZa9kAgqBqSBQZgmv3DZylLV8KyZNzOGhceL3kDVtby+CF8VAdmEA==",
"license": "MIT",
"engines": {
"node": "^20.19.0 || ^22.12.0 || >=24.0.0"
},
"peerDependencies": {
"@nestjs/common": "^7.0.0 || ^8.0.0 || ^9.0.0 || ^10.0.0 || ^11.0.0 || ^12.0.0",
"@nestjs/core": "^7.0.0 || ^8.0.0 || ^9.0.0 || ^10.0.0 || ^11.0.0 || ^12.0.0",
"reflect-metadata": "^0.1.13 || ^0.2.0"
}
},
"node_modules/@nestjs/typeorm": { "node_modules/@nestjs/typeorm": {
"version": "12.0.2", "version": "12.0.2",
"resolved": "https://registry.npmjs.org/@nestjs/typeorm/-/typeorm-12.0.2.tgz", "resolved": "https://registry.npmjs.org/@nestjs/typeorm/-/typeorm-12.0.2.tgz",
+1
View File
@@ -24,6 +24,7 @@
"@nestjs/config": "^4.0.3", "@nestjs/config": "^4.0.3",
"@nestjs/core": "^11.0.1", "@nestjs/core": "^11.0.1",
"@nestjs/platform-express": "^11.0.1", "@nestjs/platform-express": "^11.0.1",
"@nestjs/throttler": "^6.7.1",
"@nestjs/typeorm": "^12.0.2", "@nestjs/typeorm": "^12.0.2",
"altcha-lib": "^2.6.0", "altcha-lib": "^2.6.0",
"class-transformer": "^0.5.1", "class-transformer": "^0.5.1",
+24
View File
@@ -1,5 +1,7 @@
import { Module } from '@nestjs/common'; import { Module } from '@nestjs/common';
import { ConfigModule, ConfigService, registerAs } from '@nestjs/config'; import { ConfigModule, ConfigService, registerAs } from '@nestjs/config';
import { APP_GUARD } from '@nestjs/core';
import { ThrottlerGuard, ThrottlerModule } from '@nestjs/throttler';
import { TypeOrmModule } from '@nestjs/typeorm'; import { TypeOrmModule } from '@nestjs/typeorm';
import { getAltchaConfig, getAppConfig, getPostgresConfig } from './config'; import { getAltchaConfig, getAppConfig, getPostgresConfig } from './config';
import { validate } from './config/validate'; import { validate } from './config/validate';
@@ -20,6 +22,22 @@ import { Config } from './types/Config';
registerAs('altcha', getAltchaConfig) registerAs('altcha', getAltchaConfig)
] ]
}), }),
ThrottlerModule.forRootAsync({
inject: [ConfigService],
useFactory: (configService: ConfigService) => {
const { throttle } = configService.get('app') as Config['app'];
return {
throttlers: [
{
name: 'default',
ttl: throttle.ttlMs,
limit: throttle.limit
}
]
};
}
}),
TypeOrmModule.forRootAsync({ TypeOrmModule.forRootAsync({
useFactory: (configService: ConfigService) => configService.get('postgres') as Config['postgres'], useFactory: (configService: ConfigService) => configService.get('postgres') as Config['postgres'],
inject: [ConfigService] inject: [ConfigService]
@@ -28,6 +46,12 @@ import { Config } from './types/Config';
AltchaModule, AltchaModule,
StorageModule, StorageModule,
UploadModule UploadModule
],
providers: [
{
provide: APP_GUARD,
useClass: ThrottlerGuard
}
] ]
}) })
export class AppModule {} export class AppModule {}
+9 -1
View File
@@ -41,6 +41,14 @@ export const getAppConfig = (): AppConfig => {
corsOrigins: rawOrigins corsOrigins: rawOrigins
.split(',') .split(',')
.map(o => o.trim()) .map(o => o.trim())
.filter(Boolean) .filter(Boolean),
throttle: {
ttlMs: envInt('THROTTLE_TTL_MS'),
limit: envInt('THROTTLE_LIMIT')
},
uploadThrottle: {
ttlMs: envInt('THROTTLE_UPLOAD_TTL_MS'),
limit: envInt('THROTTLE_UPLOAD_LIMIT')
}
}; };
}; };
+9
View File
@@ -0,0 +1,9 @@
import { getAppConfig } from './index';
const {
uploadThrottle: { limit, ttlMs }
} = getAppConfig();
export const throttleProfiles = {
upload: { default: { limit, ttl: ttlMs } }
} as const;
+12 -24
View File
@@ -75,6 +75,18 @@ class EnvironmentVariables {
@Max(3650) @Max(3650)
NEVER_MODE_INACTIVITY_DAYS: number; NEVER_MODE_INACTIVITY_DAYS: number;
@IsNotEmpty()
@IsNumber()
@Min(1000)
@Max(3_600_000)
THROTTLE_TTL_MS: number;
@IsNotEmpty()
@IsNumber()
@Min(1)
@Max(1_000_000)
THROTTLE_LIMIT: number;
@IsNotEmpty() @IsNotEmpty()
@IsNumber() @IsNumber()
@Min(1000) @Min(1000)
@@ -86,30 +98,6 @@ class EnvironmentVariables {
@Min(1) @Min(1)
@Max(10_000) @Max(10_000)
THROTTLE_UPLOAD_LIMIT: number; THROTTLE_UPLOAD_LIMIT: number;
@IsNotEmpty()
@IsNumber()
@Min(1000)
@Max(3_600_000)
THROTTLE_HOTLINK_PER_IP_TTL_MS: number;
@IsNotEmpty()
@IsNumber()
@Min(1)
@Max(1_000_000)
THROTTLE_HOTLINK_PER_IP_LIMIT: number;
@IsNotEmpty()
@IsNumber()
@Min(1000)
@Max(3_600_000)
THROTTLE_HOTLINK_PER_ID_TTL_MS: number;
@IsNotEmpty()
@IsNumber()
@Min(1)
@Max(1_000_000)
THROTTLE_HOTLINK_PER_ID_LIMIT: number;
} }
export const validate = (config: Record<string, unknown>) => { export const validate = (config: Record<string, unknown>) => {
+3
View File
@@ -1,7 +1,10 @@
import { NodeEnv } from './NodeEnv'; import { NodeEnv } from './NodeEnv';
import { ThrottleConfig } from './ThrottleConfig';
export type AppConfig = { export type AppConfig = {
port: number; port: number;
nodeEnv: NodeEnv; nodeEnv: NodeEnv;
corsOrigins: string[]; corsOrigins: string[];
throttle: ThrottleConfig;
uploadThrottle: ThrottleConfig;
}; };
+4
View File
@@ -0,0 +1,4 @@
export type ThrottleConfig = {
ttlMs: number;
limit: number;
};