add ALTCHA challenge endpoint and env config.

GET /api/altcha/challenge, nullcart-style env validation, and ALTCHA_ENABLED wiring.
This commit is contained in:
2026-10-05 23:53:28 +02:00
parent edd97c17f7
commit 87376ea37f
12 changed files with 293 additions and 18 deletions
+129
View File
@@ -0,0 +1,129 @@
import { plainToClass } from 'class-transformer';
import { IsBoolean, IsEnum, IsNotEmpty, IsNumber, IsString, Max, Min, validateSync } from 'class-validator';
import { NodeEnv } from '../types/NodeEnv';
class EnvironmentVariables {
@IsNotEmpty()
@IsEnum(NodeEnv)
NODE_ENV: NodeEnv;
@IsNotEmpty()
@IsNumber()
@Min(1)
@Max(65535)
BACKEND_PORT: number;
@IsNotEmpty()
@IsString()
POSTGRES_USER: string;
@IsNotEmpty()
@IsString()
POSTGRES_PASSWORD: string;
@IsNotEmpty()
@IsString()
POSTGRES_DB: string;
@IsNotEmpty()
@IsString()
POSTGRES_HOST: string;
@IsNotEmpty()
@IsNumber()
@Min(1)
@Max(65535)
POSTGRES_PORT: number;
@IsNotEmpty()
@IsBoolean()
POSTGRES_MIGRATIONS_RUN: boolean;
@IsNotEmpty()
@IsString()
CORS_ORIGINS: string;
@IsNotEmpty()
@IsNumber()
@Min(1)
@Max(100)
MAX_IMAGES_PER_UPLOAD: number;
@IsNotEmpty()
@IsNumber()
@Min(1)
@Max(50 * 1024 * 1024)
MULTER_MAX_FILE_BYTES: number;
@IsNotEmpty()
@IsBoolean()
ALTCHA_ENABLED: boolean;
@IsNotEmpty()
@IsString()
ALTCHA_HMAC_KEY: string;
@IsNotEmpty()
@IsNumber()
@Min(1)
@Max(1_000_000)
ALTCHA_MAX_NUMBER: number;
@IsNotEmpty()
@IsNumber()
@Min(1)
@Max(3650)
NEVER_MODE_INACTIVITY_DAYS: number;
@IsNotEmpty()
@IsNumber()
@Min(1000)
@Max(3_600_000)
THROTTLE_UPLOAD_TTL_MS: number;
@IsNotEmpty()
@IsNumber()
@Min(1)
@Max(10_000)
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>) => {
const validatedConfig = plainToClass(EnvironmentVariables, config, {
enableImplicitConversion: true
});
const errors = validateSync(validatedConfig, {
skipMissingProperties: false
});
if (errors.length > 0) {
throw new Error(errors.toString());
}
return validatedConfig;
};