feat(security): mirror anti-DDoS blocks to Cloudflare edge via API
Gitea Actions Runner Test / test-job (push) Successful in 1s
CI / check (push) Successful in 30s
CI / tests-integration (push) Successful in 1m38s
CI / tests-unit (push) Failing after 1m40s
CI / tests-ui (push) Successful in 2m28s
CI / preflight (push) Skipped
CI / deploy (push) Skipped
Gitea Actions Runner Test / test-job (push) Successful in 1s
CI / check (push) Successful in 30s
CI / tests-integration (push) Successful in 1m38s
CI / tests-unit (push) Failing after 1m40s
CI / tests-ui (push) Successful in 2m28s
CI / preflight (push) Skipped
CI / deploy (push) Skipped
- gate creates a zone IP Access Rule (block) for proxied offenders that hit the block threshold, deduped until the tiered block expires - cloudflare-api lib: verified endpoints, create/delete/verify/list helpers, Redis-backed tracking + 30s TTL sweep (instrumentation worker + admin render) - runtime toggle cloudflareAutoBlock in antiddos config; boot default CLOUDFLARE_AUTO_BLOCK_ENABLED - admin panel: Cloudflare edge-blocks card with verify + remove-rule actions; unban also lifts the edge block - credentials live in env only (CLOUDFLARE_API_TOKEN / CLOUDFLARE_ZONE_ID)
This commit is contained in:
1 parent
f0c27eb815
commit
4479753160
9 files changed
+1157
-1
No files matched your search
@@ -23,6 +23,7 @@ export interface AntiddosConfig {
|
||||
maxViolations: number;
|
||||
blockTiers: AntiddosBlockTier[];
|
||||
globalHaltMs: number;
|
||||
cloudflareAutoBlock: boolean;
|
||||
}
|
||||
|
||||
const DEFAULT_CONFIG: AntiddosConfig = {
|
||||
@@ -39,6 +40,7 @@ const DEFAULT_CONFIG: AntiddosConfig = {
|
||||
{ minViolations: 50, ttlSeconds: 86_400 },
|
||||
],
|
||||
globalHaltMs: 10_000,
|
||||
cloudflareAutoBlock: true,
|
||||
};
|
||||
|
||||
function positiveInt(value: number | undefined, fallback: number): number {
|
||||
@@ -65,11 +67,19 @@ function parseTiers(raw: string | undefined): AntiddosBlockTier[] | null {
|
||||
return tiers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gate on a boolean-flag env value that is either already transformed to a
|
||||
* real boolean (production schema) or still a raw string (SKIP-env tests).
|
||||
*/
|
||||
function isTruthyFlag(value: string | boolean | undefined): boolean {
|
||||
return !(value === false || value === "false" || value === "0");
|
||||
}
|
||||
|
||||
/** Boot defaults from environment (explicitly set → overrides code; unset → sane value). */
|
||||
export function antiddosDefaultsFromEnv(): AntiddosConfig {
|
||||
const tiers = parseTiers(env.ANTI_DDOS_BLOCK_TIERS);
|
||||
return {
|
||||
enabled: env.ANTI_DDOS_ENABLED !== false,
|
||||
enabled: isTruthyFlag(env.ANTI_DDOS_ENABLED),
|
||||
pages: {
|
||||
limit: positiveInt(env.ANTI_DDOS_PAGES_LIMIT, DEFAULT_CONFIG.pages.limit),
|
||||
windowSeconds: positiveInt(
|
||||
@@ -114,6 +124,7 @@ export function antiddosDefaultsFromEnv(): AntiddosConfig {
|
||||
env.ANTI_DDOS_GLOBAL_HALT_MS,
|
||||
DEFAULT_CONFIG.globalHaltMs,
|
||||
),
|
||||
cloudflareAutoBlock: isTruthyFlag(env.CLOUDFLARE_AUTO_BLOCK_ENABLED),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -155,6 +166,7 @@ function sanitize(config: AntiddosConfig): AntiddosConfig {
|
||||
.sort((a, b) => a.minViolations - b.minViolations)
|
||||
: base.blockTiers,
|
||||
globalHaltMs: positiveInt(config?.globalHaltMs, base.globalHaltMs),
|
||||
cloudflareAutoBlock: config?.cloudflareAutoBlock !== false,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user