Fix rule parsing for single reverse proxies

This commit is contained in:
fuomag9
2026-03-04 21:16:11 +01:00
parent 77d3e35c63
commit 7341070c0d
14 changed files with 685 additions and 143 deletions

View File

@@ -2,6 +2,7 @@
import {
Box,
Button,
Checkbox,
Collapse,
Divider,
@@ -12,12 +13,22 @@ import {
Typography,
} from "@mui/material";
import GppBadIcon from "@mui/icons-material/GppBad";
import ContentCopyIcon from "@mui/icons-material/ContentCopy";
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
import { useState } from "react";
import { type WafHostConfig } from "@/src/lib/models/proxy-hosts";
import { WafRuleExclusions } from "./WafRuleExclusions";
type WafMode = "merge" | "override";
type EngineMode = "Off" | "DetectionOnly" | "On";
const QUICK_TEMPLATES = [
{ label: "Allow IP", snippet: `SecRule REMOTE_ADDR "@ipMatch 1.2.3.4" "id:9000,phase:1,allow,nolog,msg:'Allow IP'"` },
{ label: "Disable WAF for path", snippet: `SecRule REQUEST_URI "@beginsWith /api/" "id:9001,phase:1,ctl:ruleEngine=Off,nolog"` },
{ label: "Remove XSS rules", snippet: `SecRuleRemoveByTag "attack-xss"` },
{ label: "Block User-Agent", snippet: `SecRule REQUEST_HEADERS:User-Agent "@contains badbot" "id:9002,phase:1,deny,status:403,log"` },
];
type Props = {
value?: WafHostConfig | null;
showModeSelector?: boolean;
@@ -29,6 +40,7 @@ export function WafFields({ value, showModeSelector = true }: Props) {
const [engineMode, setEngineMode] = useState<EngineMode>(value?.mode ?? "DetectionOnly");
const [loadCrs, setLoadCrs] = useState(value?.load_owasp_crs ?? true);
const [customDirectives, setCustomDirectives] = useState(value?.custom_directives ?? "");
const [showTemplates, setShowTemplates] = useState(false);
return (
<Box
@@ -204,6 +216,11 @@ export function WafFields({ value, showModeSelector = true }: Props) {
}
/>
{/* Excluded rule IDs */}
<Box mt={1.5}>
<WafRuleExclusions value={value?.excluded_rule_ids} />
</Box>
{/* Custom directives */}
<Box mt={1.5}>
<TextField
@@ -219,6 +236,34 @@ export function WafFields({ value, showModeSelector = true }: Props) {
fullWidth
/>
</Box>
{/* Quick Templates */}
<Box mt={0.5}>
<Button
size="small"
endIcon={<ExpandMoreIcon sx={{ transform: showTemplates ? "rotate(180deg)" : "none", transition: "transform 0.2s" }} />}
onClick={() => setShowTemplates((v) => !v)}
sx={{ color: "text.secondary", textTransform: "none", px: 0 }}
>
Quick Templates
</Button>
<Collapse in={showTemplates}>
<Stack spacing={0.75} mt={0.75}>
{QUICK_TEMPLATES.map((t) => (
<Button
key={t.label}
size="small"
variant="outlined"
startIcon={<ContentCopyIcon fontSize="inherit" />}
onClick={() => setCustomDirectives((prev) => prev ? `${prev}\n${t.snippet}` : t.snippet)}
sx={{ justifyContent: "flex-start", textTransform: "none", fontFamily: "monospace", fontSize: "0.72rem" }}
>
{t.label}
</Button>
))}
</Stack>
</Collapse>
</Box>
</Box>
</Collapse>
</Box>