Neu: eigene WAF-App-Profile (benannte, wiederverwendbare Rule-ID-Ausnahme- Bündel) — zentrale Bibliothek im UI (eigener Tab), pro Domain zuweisbar, Built-in-OWASP-Plugins bleiben read-only + als Vorlage klonbar. Nur reine Rule-IDs/Ranges (keine SecLang-Ausführung, injektionssicher). - Migration 0047: Tabelle waf_app_profiles (repliziert via reconcile) + waf_configs.app_profiles. - Service/Handler: CRUD (/waf/profiles), Built-ins geschützt (builtin=false-Gate). - Agent-Loader: app_profiles → in effektive rule_exclusions gemerged; ihr updated_at hebt das effektive updated_at der Domain → Engine-Rebuild bei Profil-Edit. - UI: Profile-Tab (Liste/Editor mit durchsuchbaren Rule-IDs) + Multi-Select im Domain-Drawer. FIX (wichtig): ListAllWithDomain — der EINZIGE Loader des laufenden WAF-Agents — selektierte crs_plugins nie. Dadurch war cfg.CRSPlugins im Agent immer leer und KEIN Built-in-CRS-Plugin (Nextcloud/WordPress/Drupal) wurde je in die Engine inkludiert. Jetzt geladen (+ app_profiles). Die per-Domain-Plugin-Wahl wirkt damit erstmals tatsächlich. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
44 lines
2.7 KiB
Go
44 lines
2.7 KiB
Go
package models
|
||
|
||
import "time"
|
||
|
||
// WafConfig holds the per-domain WAF policy.
|
||
// Default on creation: enabled=false, mode=detection, paranoia_level=1.
|
||
type WafConfig struct {
|
||
ID int64 `gorm:"primaryKey" json:"id"`
|
||
DomainID int64 `gorm:"column:domain_id;uniqueIndex" json:"domain_id"`
|
||
Enabled bool `gorm:"column:enabled" json:"enabled"`
|
||
Mode string `gorm:"column:mode" json:"mode"` // "detection" | "blocking"
|
||
ParanoiaLevel int `gorm:"column:paranoia_level" json:"paranoia_level"` // 1–4
|
||
RuleExclusions []string `gorm:"column:rule_exclusions;type:text[]" json:"rule_exclusions"`
|
||
// CRSPlugins: aktivierte OWASP-CRS-App-Exclusion-Plugins (z. B.
|
||
// "nextcloud","wordpress"). Der Renderer inkludiert je Plugin dessen
|
||
// config/before/after-Dateien aus <crsDir>/plugins/.
|
||
CRSPlugins []string `gorm:"column:crs_plugins;type:text[]" json:"crs_plugins"`
|
||
// AppProfiles: zugewiesene benutzerdefinierte WAF-App-Profile (Namen aus
|
||
// waf_app_profiles). Ihre rule_exclusions werden im Agent in die effektiven
|
||
// Ausnahmen dieser Domain gemischt.
|
||
AppProfiles []string `gorm:"column:app_profiles;type:text[]" json:"app_profiles"`
|
||
ExclusionNotes map[string]string `gorm:"column:exclusion_notes;type:jsonb" json:"exclusion_notes"` // rule_id → note
|
||
TrustedProxies []string `gorm:"column:trusted_proxies;type:text[]" json:"trusted_proxies"`
|
||
CustomRules string `gorm:"column:custom_rules" json:"custom_rules"`
|
||
UpdatedAt time.Time `gorm:"column:updated_at" json:"updated_at"`
|
||
}
|
||
|
||
func (WafConfig) TableName() string { return "waf_configs" }
|
||
|
||
// WafAppProfile ist ein benanntes, wiederverwendbares Bündel von CRS-Rule-
|
||
// Exclusions (reine Rule-IDs/Ranges). Built-in-Profile (builtin=true) sind
|
||
// read-only; benutzerdefinierte sind im UI editierbar und pro Domain zuweisbar.
|
||
type WafAppProfile struct {
|
||
ID int64 `gorm:"primaryKey" json:"id"`
|
||
Name string `gorm:"column:name;uniqueIndex" json:"name"`
|
||
Description string `gorm:"column:description" json:"description"`
|
||
RuleExclusions []string `gorm:"column:rule_exclusions;type:text[]" json:"rule_exclusions"`
|
||
Builtin bool `gorm:"column:builtin" json:"builtin"`
|
||
CreatedAt time.Time `gorm:"column:created_at" json:"created_at"`
|
||
UpdatedAt time.Time `gorm:"column:updated_at" json:"updated_at"`
|
||
}
|
||
|
||
func (WafAppProfile) TableName() string { return "waf_app_profiles" }
|