diff --git a/pkg/exprhelpers/expr_lib.go b/pkg/exprhelpers/expr_lib.go index db191b84a..b4f18a8a3 100644 --- a/pkg/exprhelpers/expr_lib.go +++ b/pkg/exprhelpers/expr_lib.go @@ -6,438 +6,438 @@ import ( "github.com/crowdsecurity/crowdsec/pkg/cticlient" ) -type exprCustomFunc struct { - name string - function func(params ...any) (any, error) - signature []interface{} +type ExprCustomFunc struct { + Name string + Function func(params ...any) (any, error) + Signature []interface{} } -var exprFuncs = []exprCustomFunc{ +var exprFuncs = []ExprCustomFunc{ { - name: "CrowdsecCTI", - function: CrowdsecCTI, - signature: []interface{}{ + Name: "CrowdsecCTI", + Function: CrowdsecCTI, + Signature: []interface{}{ new(func(string) (*cticlient.SmokeItem, error)), }, }, { - name: "Flatten", - function: Flatten, - signature: []interface{}{}, + Name: "Flatten", + Function: Flatten, + Signature: []interface{}{}, }, { - name: "Distinct", - function: Distinct, - signature: []interface{}{}, + Name: "Distinct", + Function: Distinct, + Signature: []interface{}{}, }, { - name: "FlattenDistinct", - function: FlattenDistinct, - signature: []interface{}{}, + Name: "FlattenDistinct", + Function: FlattenDistinct, + Signature: []interface{}{}, }, { - name: "Distance", - function: Distance, - signature: []interface{}{ + Name: "Distance", + Function: Distance, + Signature: []interface{}{ new(func(string, string, string, string) (float64, error)), }, }, { - name: "GetFromStash", - function: GetFromStash, - signature: []interface{}{ + Name: "GetFromStash", + Function: GetFromStash, + Signature: []interface{}{ new(func(string, string) (string, error)), }, }, { - name: "Atof", - function: Atof, - signature: []interface{}{ + Name: "Atof", + Function: Atof, + Signature: []interface{}{ new(func(string) float64), }, }, { - name: "JsonExtract", - function: JsonExtract, - signature: []interface{}{ + Name: "JsonExtract", + Function: JsonExtract, + Signature: []interface{}{ new(func(string, string) string), }, }, { - name: "JsonExtractUnescape", - function: JsonExtractUnescape, - signature: []interface{}{ + Name: "JsonExtractUnescape", + Function: JsonExtractUnescape, + Signature: []interface{}{ new(func(string, ...string) string), }, }, { - name: "JsonExtractLib", - function: JsonExtractLib, - signature: []interface{}{ + Name: "JsonExtractLib", + Function: JsonExtractLib, + Signature: []interface{}{ new(func(string, ...string) string), }, }, { - name: "JsonExtractSlice", - function: JsonExtractSlice, - signature: []interface{}{ + Name: "JsonExtractSlice", + Function: JsonExtractSlice, + Signature: []interface{}{ new(func(string, string) []interface{}), }, }, { - name: "JsonExtractObject", - function: JsonExtractObject, - signature: []interface{}{ + Name: "JsonExtractObject", + Function: JsonExtractObject, + Signature: []interface{}{ new(func(string, string) map[string]interface{}), }, }, { - name: "ToJsonString", - function: ToJson, - signature: []interface{}{ + Name: "ToJsonString", + Function: ToJson, + Signature: []interface{}{ new(func(interface{}) string), }, }, { - name: "File", - function: File, - signature: []interface{}{ + Name: "File", + Function: File, + Signature: []interface{}{ new(func(string) []string), }, }, { - name: "RegexpInFile", - function: RegexpInFile, - signature: []interface{}{ + Name: "RegexpInFile", + Function: RegexpInFile, + Signature: []interface{}{ new(func(string, string) bool), }, }, { - name: "Upper", - function: Upper, - signature: []interface{}{ + Name: "Upper", + Function: Upper, + Signature: []interface{}{ new(func(string) string), }, }, { - name: "Lower", - function: Lower, - signature: []interface{}{ + Name: "Lower", + Function: Lower, + Signature: []interface{}{ new(func(string) string), }, }, { - name: "IpInRange", - function: IpInRange, - signature: []interface{}{ + Name: "IpInRange", + Function: IpInRange, + Signature: []interface{}{ new(func(string, string) bool), }, }, { - name: "TimeNow", - function: TimeNow, - signature: []interface{}{ + Name: "TimeNow", + Function: TimeNow, + Signature: []interface{}{ new(func() string), }, }, { - name: "ParseUri", - function: ParseUri, - signature: []interface{}{ + Name: "ParseUri", + Function: ParseUri, + Signature: []interface{}{ new(func(string) map[string][]string), }, }, { - name: "PathUnescape", - function: PathUnescape, - signature: []interface{}{ + Name: "PathUnescape", + Function: PathUnescape, + Signature: []interface{}{ new(func(string) string), }, }, { - name: "QueryUnescape", - function: QueryUnescape, - signature: []interface{}{ + Name: "QueryUnescape", + Function: QueryUnescape, + Signature: []interface{}{ new(func(string) string), }, }, { - name: "PathEscape", - function: PathEscape, - signature: []interface{}{ + Name: "PathEscape", + Function: PathEscape, + Signature: []interface{}{ new(func(string) string), }, }, { - name: "QueryEscape", - function: QueryEscape, - signature: []interface{}{ + Name: "QueryEscape", + Function: QueryEscape, + Signature: []interface{}{ new(func(string) string), }, }, { - name: "XMLGetAttributeValue", - function: XMLGetAttributeValue, - signature: []interface{}{ + Name: "XMLGetAttributeValue", + Function: XMLGetAttributeValue, + Signature: []interface{}{ new(func(string, string, string) string), }, }, { - name: "XMLGetNodeValue", - function: XMLGetNodeValue, - signature: []interface{}{ + Name: "XMLGetNodeValue", + Function: XMLGetNodeValue, + Signature: []interface{}{ new(func(string, string) string), }, }, { - name: "IpToRange", - function: IpToRange, - signature: []interface{}{ + Name: "IpToRange", + Function: IpToRange, + Signature: []interface{}{ new(func(string, string) string), }, }, { - name: "IsIPV6", - function: IsIPV6, - signature: []interface{}{ + Name: "IsIPV6", + Function: IsIPV6, + Signature: []interface{}{ new(func(string) bool), }, }, { - name: "IsIPV4", - function: IsIPV4, - signature: []interface{}{ + Name: "IsIPV4", + Function: IsIPV4, + Signature: []interface{}{ new(func(string) bool), }, }, { - name: "IsIP", - function: IsIP, - signature: []interface{}{ + Name: "IsIP", + Function: IsIP, + Signature: []interface{}{ new(func(string) bool), }, }, { - name: "LookupHost", - function: LookupHost, - signature: []interface{}{ + Name: "LookupHost", + Function: LookupHost, + Signature: []interface{}{ new(func(string) []string), }, }, { - name: "GetDecisionsCount", - function: GetDecisionsCount, - signature: []interface{}{ + Name: "GetDecisionsCount", + Function: GetDecisionsCount, + Signature: []interface{}{ new(func(string) int), }, }, { - name: "GetDecisionsSinceCount", - function: GetDecisionsSinceCount, - signature: []interface{}{ + Name: "GetDecisionsSinceCount", + Function: GetDecisionsSinceCount, + Signature: []interface{}{ new(func(string, string) int), }, }, { - name: "Sprintf", - function: Sprintf, - signature: []interface{}{ + Name: "Sprintf", + Function: Sprintf, + Signature: []interface{}{ new(func(string, ...interface{}) string), }, }, { - name: "ParseUnix", - function: ParseUnix, - signature: []interface{}{ + Name: "ParseUnix", + Function: ParseUnix, + Signature: []interface{}{ new(func(string) string), }, }, { - name: "SetInStash", //FIXME: signature will probably blow everything up - function: SetInStash, - signature: []interface{}{ + Name: "SetInStash", //FIXME: signature will probably blow everything up + Function: SetInStash, + Signature: []interface{}{ new(func(string, string, string, *time.Duration) error), }, }, { - name: "Fields", - function: Fields, - signature: []interface{}{ + Name: "Fields", + Function: Fields, + Signature: []interface{}{ new(func(string) []string), }, }, { - name: "Index", - function: Index, - signature: []interface{}{ + Name: "Index", + Function: Index, + Signature: []interface{}{ new(func(string, string) int), }, }, { - name: "IndexAny", - function: IndexAny, - signature: []interface{}{ + Name: "IndexAny", + Function: IndexAny, + Signature: []interface{}{ new(func(string, string) int), }, }, { - name: "Join", - function: Join, - signature: []interface{}{ + Name: "Join", + Function: Join, + Signature: []interface{}{ new(func([]string, string) string), }, }, { - name: "Split", - function: Split, - signature: []interface{}{ + Name: "Split", + Function: Split, + Signature: []interface{}{ new(func(string, string) []string), }, }, { - name: "SplitAfter", - function: SplitAfter, - signature: []interface{}{ + Name: "SplitAfter", + Function: SplitAfter, + Signature: []interface{}{ new(func(string, string) []string), }, }, { - name: "SplitAfterN", - function: SplitAfterN, - signature: []interface{}{ + Name: "SplitAfterN", + Function: SplitAfterN, + Signature: []interface{}{ new(func(string, string, int) []string), }, }, { - name: "SplitN", - function: SplitN, - signature: []interface{}{ + Name: "SplitN", + Function: SplitN, + Signature: []interface{}{ new(func(string, string, int) []string), }, }, { - name: "Replace", - function: Replace, - signature: []interface{}{ + Name: "Replace", + Function: Replace, + Signature: []interface{}{ new(func(string, string, string, int) string), }, }, { - name: "ReplaceAll", - function: ReplaceAll, - signature: []interface{}{ + Name: "ReplaceAll", + Function: ReplaceAll, + Signature: []interface{}{ new(func(string, string, string) string), }, }, { - name: "Trim", - function: Trim, - signature: []interface{}{ + Name: "Trim", + Function: Trim, + Signature: []interface{}{ new(func(string, string) string), }, }, { - name: "TrimLeft", - function: TrimLeft, - signature: []interface{}{ + Name: "TrimLeft", + Function: TrimLeft, + Signature: []interface{}{ new(func(string, string) string), }, }, { - name: "TrimRight", - function: TrimRight, - signature: []interface{}{ + Name: "TrimRight", + Function: TrimRight, + Signature: []interface{}{ new(func(string, string) string), }, }, { - name: "TrimSpace", - function: TrimSpace, - signature: []interface{}{ + Name: "TrimSpace", + Function: TrimSpace, + Signature: []interface{}{ new(func(string) string), }, }, { - name: "TrimPrefix", - function: TrimPrefix, - signature: []interface{}{ + Name: "TrimPrefix", + Function: TrimPrefix, + Signature: []interface{}{ new(func(string, string) string), }, }, { - name: "TrimSuffix", - function: TrimSuffix, - signature: []interface{}{ + Name: "TrimSuffix", + Function: TrimSuffix, + Signature: []interface{}{ new(func(string, string) string), }, }, { - name: "Get", - function: Get, - signature: []interface{}{ + Name: "Get", + Function: Get, + Signature: []interface{}{ new(func([]string, int) string), }, }, { - name: "ToString", - function: ToString, - signature: []interface{}{ + Name: "ToString", + Function: ToString, + Signature: []interface{}{ new(func(interface{}) string), }, }, { - name: "Match", - function: Match, - signature: []interface{}{ + Name: "Match", + Function: Match, + Signature: []interface{}{ new(func(string, string) bool), }, }, { - name: "KeyExists", - function: KeyExists, - signature: []interface{}{ + Name: "KeyExists", + Function: KeyExists, + Signature: []interface{}{ new(func(string, map[string]any) bool), }, }, { - name: "LogInfo", - function: LogInfo, - signature: []interface{}{ + Name: "LogInfo", + Function: LogInfo, + Signature: []interface{}{ new(func(string, ...interface{}) bool), }, }, { - name: "B64Decode", - function: B64Decode, - signature: []interface{}{ + Name: "B64Decode", + Function: B64Decode, + Signature: []interface{}{ new(func(string) string), }, }, { - name: "UnmarshalJSON", - function: UnmarshalJSON, - signature: []interface{}{ + Name: "UnmarshalJSON", + Function: UnmarshalJSON, + Signature: []interface{}{ new(func(string, map[string]interface{}, string) error), }, }, { - name: "ParseKV", - function: ParseKV, - signature: []interface{}{ + Name: "ParseKV", + Function: ParseKV, + Signature: []interface{}{ new(func(string, map[string]interface{}, string) error), }, }, { - name: "Hostname", - function: Hostname, - signature: []interface{}{ + Name: "Hostname", + Function: Hostname, + Signature: []interface{}{ new(func() (string, error)), }, }, { - name: "FloatApproxEqual", - function: FloatApproxEqual, - signature: []interface{}{ + Name: "FloatApproxEqual", + Function: FloatApproxEqual, + Signature: []interface{}{ new(func(float64, float64) bool), }, }, diff --git a/pkg/exprhelpers/helpers.go b/pkg/exprhelpers/helpers.go index 79a621c7d..350dd2974 100644 --- a/pkg/exprhelpers/helpers.go +++ b/pkg/exprhelpers/helpers.go @@ -60,9 +60,9 @@ func GetExprOptions(ctx map[string]interface{}) []expr.Option { exprFunctionOptions = []expr.Option{} for _, function := range exprFuncs { exprFunctionOptions = append(exprFunctionOptions, - expr.Function(function.name, - function.function, - function.signature..., + expr.Function(function.Name, + function.Function, + function.Signature..., )) } } diff --git a/pkg/waf/request.go b/pkg/waf/request.go index 5e792a13b..6029adc3e 100644 --- a/pkg/waf/request.go +++ b/pkg/waf/request.go @@ -58,12 +58,12 @@ type ReqDumpFilter struct { ArgsDrop bool } -func (r *ParsedRequest) DumpRequest(params ...any) *ReqDumpFilter { +func (r *ParsedRequest) DumpRequest(params ...any) (any, error) { filter := ReqDumpFilter{} filter.BodyDrop = true filter.HeadersNameFilters = []string{"cookie", "authorization"} filter.req = r - return &filter + return &filter, nil } // clear filters diff --git a/pkg/waf/request_test.go b/pkg/waf/request_test.go index 2625e11f5..b4f50761c 100644 --- a/pkg/waf/request_test.go +++ b/pkg/waf/request_test.go @@ -161,7 +161,8 @@ func TestBodyDumper(t *testing.T) { for idx, test := range tests { t.Run(test.name, func(t *testing.T) { - orig_dr := test.req.DumpRequest() + tmp_dr, _ := test.req.DumpRequest() + orig_dr := tmp_dr.(*ReqDumpFilter) result := test.filter(orig_dr).GetFilteredRequest() if len(result.Body) != len(test.expect.Body) { diff --git a/pkg/waf/waap.go b/pkg/waf/waap.go index 2820bb8c4..497d4eef7 100644 --- a/pkg/waf/waap.go +++ b/pkg/waf/waap.go @@ -34,19 +34,26 @@ const ( func (h *Hook) Build(hookStage int) error { ctx := map[string]interface{}{} + opts := []expr.Option{} switch hookStage { case hookOnLoad: - ctx = GetOnLoadEnv(&WaapRuntimeConfig{}) + opts = GetOnLoadEnv(ctx, &WaapRuntimeConfig{}) case hookPreEval: - ctx = GetPreEvalEnv(&WaapRuntimeConfig{}, &ParsedRequest{}) + ctx["IsInBand"] = true + ctx["IsOutBand"] = true + opts = GetPreEvalEnv(ctx, &WaapRuntimeConfig{}, &ParsedRequest{}) case hookPostEval: - ctx = GetPostEvalEnv(&WaapRuntimeConfig{}, &ParsedRequest{}) + ctx["IsInBand"] = true + ctx["IsOutBand"] = true + opts = GetPostEvalEnv(ctx, &WaapRuntimeConfig{}, &ParsedRequest{}) case hookOnMatch: - ctx = GetOnMatchEnv(&WaapRuntimeConfig{}, &ParsedRequest{}, types.Event{}) + ctx["evt"] = types.Event{} + ctx["IsInBand"] = true + ctx["IsOutBand"] = true + opts = GetOnMatchEnv(ctx, &WaapRuntimeConfig{}, &ParsedRequest{}) } - opts := GetExprWAFOptions(ctx) if h.Filter != "" { - program, err := expr.Compile(h.Filter, opts...) //FIXME: opts + program, err := expr.Compile(h.Filter, opts...) if err != nil { return fmt.Errorf("unable to compile filter %s : %w", h.Filter, err) } @@ -283,7 +290,7 @@ func (wc *WaapConfig) Build() (*WaapRuntimeConfig, error) { func (w *WaapRuntimeConfig) ProcessOnLoadRules() error { for _, rule := range w.CompiledOnLoad { if rule.FilterExpr != nil { - output, err := exprhelpers.Run(rule.FilterExpr, GetOnLoadEnv(w), w.Logger, w.Logger.Level >= log.DebugLevel) + output, err := exprhelpers.Run(rule.FilterExpr, map[string]interface{}{}, w.Logger, w.Logger.Level >= log.DebugLevel) if err != nil { return fmt.Errorf("unable to run waap on_load filter %s : %w", rule.Filter, err) } @@ -299,7 +306,7 @@ func (w *WaapRuntimeConfig) ProcessOnLoadRules() error { } } for _, applyExpr := range rule.ApplyExpr { - _, err := exprhelpers.Run(applyExpr, GetOnLoadEnv(w), w.Logger, w.Logger.Level >= log.DebugLevel) + _, err := exprhelpers.Run(applyExpr, map[string]interface{}{}, w.Logger, w.Logger.Level >= log.DebugLevel) if err != nil { log.Errorf("unable to apply waap on_load expr: %s", err) continue @@ -310,10 +317,14 @@ func (w *WaapRuntimeConfig) ProcessOnLoadRules() error { } func (w *WaapRuntimeConfig) ProcessOnMatchRules(request *ParsedRequest, evt types.Event) error { - + ctx := map[string]interface{}{ + "evt": evt, + "IsInBand": request.IsInBand, + "IsOutBand": request.IsOutBand, + } for _, rule := range w.CompiledOnMatch { if rule.FilterExpr != nil { - output, err := exprhelpers.Run(rule.FilterExpr, GetOnMatchEnv(w, request, evt), w.Logger, w.Logger.Level >= log.DebugLevel) + output, err := exprhelpers.Run(rule.FilterExpr, ctx, w.Logger, w.Logger.Level >= log.DebugLevel) if err != nil { return fmt.Errorf("unable to run waap on_match filter %s : %w", rule.Filter, err) } @@ -329,7 +340,7 @@ func (w *WaapRuntimeConfig) ProcessOnMatchRules(request *ParsedRequest, evt type } } for _, applyExpr := range rule.ApplyExpr { - _, err := exprhelpers.Run(applyExpr, GetOnMatchEnv(w, request, evt), w.Logger, w.Logger.Level >= log.DebugLevel) + _, err := exprhelpers.Run(applyExpr, ctx, w.Logger, w.Logger.Level >= log.DebugLevel) if err != nil { log.Errorf("unable to apply waap on_match expr: %s", err) continue @@ -340,9 +351,13 @@ func (w *WaapRuntimeConfig) ProcessOnMatchRules(request *ParsedRequest, evt type } func (w *WaapRuntimeConfig) ProcessPreEvalRules(request *ParsedRequest) error { + ctx := map[string]interface{}{ + "IsInBand": request.IsInBand, + "IsOutBand": request.IsOutBand, + } for _, rule := range w.CompiledPreEval { if rule.FilterExpr != nil { - output, err := exprhelpers.Run(rule.FilterExpr, GetPreEvalEnv(w, request), w.Logger, w.Logger.Level >= log.DebugLevel) + output, err := exprhelpers.Run(rule.FilterExpr, GetPreEvalEnv(ctx, w, request), w.Logger, w.Logger.Level >= log.DebugLevel) if err != nil { return fmt.Errorf("unable to run waap pre_eval filter %s : %w", rule.Filter, err) } @@ -359,7 +374,7 @@ func (w *WaapRuntimeConfig) ProcessPreEvalRules(request *ParsedRequest) error { } // here means there is no filter or the filter matched for _, applyExpr := range rule.ApplyExpr { - _, err := exprhelpers.Run(applyExpr, GetPreEvalEnv(w, request), w.Logger, w.Logger.Level >= log.DebugLevel) + _, err := exprhelpers.Run(applyExpr, ctx, w.Logger, w.Logger.Level >= log.DebugLevel) if err != nil { log.Errorf("unable to apply waap pre_eval expr: %s", err) continue @@ -371,9 +386,13 @@ func (w *WaapRuntimeConfig) ProcessPreEvalRules(request *ParsedRequest) error { } func (w *WaapRuntimeConfig) ProcessPostEvalRules(request *ParsedRequest) error { + ctx := map[string]interface{}{ + "IsInBand": request.IsInBand, + "IsOutBand": request.IsOutBand, + } for _, rule := range w.CompiledPostEval { if rule.FilterExpr != nil { - output, err := exprhelpers.Run(rule.FilterExpr, GetPostEvalEnv(w, request), w.Logger, w.Logger.Level >= log.DebugLevel) + output, err := exprhelpers.Run(rule.FilterExpr, ctx, w.Logger, w.Logger.Level >= log.DebugLevel) if err != nil { return fmt.Errorf("unable to run waap post_eval filter %s : %w", rule.Filter, err) } @@ -390,7 +409,7 @@ func (w *WaapRuntimeConfig) ProcessPostEvalRules(request *ParsedRequest) error { } // here means there is no filter or the filter matched for _, applyExpr := range rule.ApplyExpr { - _, err := exprhelpers.Run(applyExpr, GetPostEvalEnv(w, request), w.Logger, w.Logger.Level >= log.DebugLevel) + _, err := exprhelpers.Run(applyExpr, ctx, w.Logger, w.Logger.Level >= log.DebugLevel) if err != nil { log.Errorf("unable to apply waap post_eval expr: %s", err) continue @@ -551,6 +570,7 @@ func (w *WaapRuntimeConfig) SetActionByID(params ...any) (any, error) { // func (w *WaapRuntimeConfig) SetActionByID(name string, action string) error { func (w *WaapRuntimeConfig) SetActionByName(params ...any) (any, error) { + fmt.Printf("%v+\n", w) if w.RemediationByTag == nil { w.RemediationByTag = make(map[string]string) } diff --git a/pkg/waf/waf_expr_lib.go b/pkg/waf/waf_expr_lib.go index 717b1bdff..b2a80723d 100644 --- a/pkg/waf/waf_expr_lib.go +++ b/pkg/waf/waf_expr_lib.go @@ -1,11 +1,3 @@ package waf //This is a copy paste from expr_lib.go, we probably want to only have one ? - -type exprCustomFunc struct { - name string - function func(params ...any) (any, error) - signature []interface{} -} - -var exprFuncs = []exprCustomFunc{} diff --git a/pkg/waf/waf_helpers.go b/pkg/waf/waf_helpers.go index ced1b68e7..aba4ec19b 100644 --- a/pkg/waf/waf_helpers.go +++ b/pkg/waf/waf_helpers.go @@ -3,40 +3,183 @@ package waf import ( "github.com/antonmedv/expr" "github.com/crowdsecurity/crowdsec/pkg/exprhelpers" - "github.com/crowdsecurity/crowdsec/pkg/types" ) -func GetExprWAFOptions(ctx map[string]interface{}) []expr.Option { +var exprOnLoadOptions = []expr.Option{} +var exprPreEvalOptions = []expr.Option{} +var exprPostEvalOptions = []expr.Option{} +var exprOnMatchOptions = []expr.Option{} + +func GetOnLoadEnv(ctx map[string]interface{}, w *WaapRuntimeConfig) []expr.Option { baseHelpers := exprhelpers.GetExprOptions(ctx) - - for _, function := range exprFuncs { - baseHelpers = append(baseHelpers, - expr.Function(function.name, - function.function, - function.signature..., - )) + onLoadHelpers := []exprhelpers.ExprCustomFunc{ + { + Name: "RemoveInBandRuleByID", + Function: w.DisableInBandRuleByID, + Signature: []interface{}{ + new(func(int) error), + }, + }, + { + Name: "RemoveInBandRuleByTag", + Function: w.DisableInBandRuleByTag, + Signature: []interface{}{ + new(func(string) error), + }, + }, + { + Name: "RemoveInBandRuleByName", + Function: w.DisableInBandRuleByName, + Signature: []interface{}{ + new(func(string) error), + }, + }, + { + Name: "RemoveOutBandRuleByID", + Function: w.DisableOutBandRuleByID, + Signature: []interface{}{ + new(func(int) error), + }, + }, + { + Name: "RemoveOutBandRuleByTag", + Function: w.DisableOutBandRuleByTag, + Signature: []interface{}{ + new(func(string) error), + }, + }, + { + Name: "RemoveOutBandRuleByName", + Function: w.DisableOutBandRuleByName, + Signature: []interface{}{ + new(func(string) error), + }, + }, + { + Name: "SetRemediationByTag", + Function: w.SetActionByTag, + Signature: []interface{}{ + new(func(string, string) error), + }, + }, + { + Name: "SetRemediationByID", + Function: w.SetActionByID, + Signature: []interface{}{ + new(func(int, string) error), + }, + }, + { + Name: "SetRemediationByName", + Function: w.SetActionByName, + Signature: []interface{}{ + new(func(string, string) error), + }, + }, } - return baseHelpers + + if len(exprOnLoadOptions) == 0 { + for _, function := range onLoadHelpers { + exprOnLoadOptions = append(exprOnLoadOptions, + expr.Function( + function.Name, + function.Function, + function.Signature..., + ), + ) + } + exprOnLoadOptions = append(exprOnLoadOptions, baseHelpers...) + } + + return exprOnLoadOptions } -func GetOnLoadEnv(w *WaapRuntimeConfig) map[string]interface{} { - //FIXME: use expr.Function instead of this - return map[string]interface{}{ - "RemoveInBandRuleByID": w.DisableInBandRuleByID, - "RemoveInBandRuleByTag": w.DisableInBandRuleByTag, - "RemoveInBandRuleByName": w.DisableInBandRuleByName, - "RemoveOutBandRuleByID": w.DisableOutBandRuleByID, - "RemoveOutBandRuleByTag": w.DisableOutBandRuleByTag, - "RemoveOutBandRuleByName": w.DisableOutBandRuleByName, - "SetRemediationByTag": w.SetActionByTag, - "SetRemediationByID": w.SetActionByID, - "SetRemediationByName": w.SetActionByName, - } -} +func GetPreEvalEnv(ctx map[string]interface{}, w *WaapRuntimeConfig, request *ParsedRequest) []expr.Option { + + baseHelpers := exprhelpers.GetExprOptions(ctx) + preEvalHelpers := []exprhelpers.ExprCustomFunc{ + { + Name: "RemoveInBandRuleByID", + Function: w.RemoveInbandRuleByID, + Signature: []interface{}{ + new(func(int) error), + }, + }, + { + Name: "RemoveInBandRuleByTag", + Function: w.RemoveInbandRuleByTag, + Signature: []interface{}{ + new(func(string) error), + }, + }, + { + Name: "RemoveInBandRuleByName", + Function: w.RemoveInbandRuleByName, + Signature: []interface{}{ + new(func(string) error), + }, + }, + { + Name: "RemoveOutBandRuleByID", + Function: w.RemoveOutbandRuleByID, + Signature: []interface{}{ + new(func(int) error), + }, + }, + { + Name: "RemoveOutBandRuleByTag", + Function: w.RemoveOutbandRuleByTag, + Signature: []interface{}{ + new(func(string) error), + }, + }, + { + Name: "RemoveOutBandRuleByName", + Function: w.RemoveOutbandRuleByName, + Signature: []interface{}{ + new(func(string) error), + }, + }, + { + Name: "SetRemediationByTag", + Function: w.SetActionByTag, + Signature: []interface{}{ + new(func(string, string) error), + }, + }, + { + Name: "SetRemediationByID", + Function: w.SetActionByID, + Signature: []interface{}{ + new(func(int, string) error), + }, + }, + { + Name: "SetRemediationByName", + Function: w.SetActionByName, + Signature: []interface{}{ + new(func(string, string) error), + }, + }, + } + + if len(exprPreEvalOptions) == 0 { + for _, function := range preEvalHelpers { + exprPreEvalOptions = append(exprPreEvalOptions, + expr.Function( + function.Name, + function.Function, + function.Signature..., + ), + ) + } + exprPreEvalOptions = append(exprPreEvalOptions, baseHelpers...) + } + + return exprPreEvalOptions -func GetPreEvalEnv(w *WaapRuntimeConfig, request *ParsedRequest) map[string]interface{} { //FIXME: use expr.Function instead of this - return map[string]interface{}{ + /*return map[string]interface{}{ "IsInBand": request.IsInBand, "IsOutBand": request.IsOutBand, "RemoveInBandRuleByID": w.RemoveInbandRuleByID, @@ -48,20 +191,114 @@ func GetPreEvalEnv(w *WaapRuntimeConfig, request *ParsedRequest) map[string]inte "SetRemediationByTag": w.SetActionByTag, "SetRemediationByID": w.SetActionByID, "SetRemediationByName": w.SetActionByName, - } + }*/ } -func GetPostEvalEnv(w *WaapRuntimeConfig, request *ParsedRequest) map[string]interface{} { - //FIXME: use expr.Function instead of this +func GetPostEvalEnv(ctx map[string]interface{}, w *WaapRuntimeConfig, request *ParsedRequest) []expr.Option { + baseHelpers := exprhelpers.GetExprOptions(ctx) + postEvalHelpers := []exprhelpers.ExprCustomFunc{ + { + Name: "DumpRequest", + Function: request.DumpRequest, + Signature: []interface{}{ + new(func() *ReqDumpFilter), + }, + }, + } + + if len(exprPostEvalOptions) == 0 { + for _, function := range postEvalHelpers { + exprPostEvalOptions = append(exprPostEvalOptions, + expr.Function( + function.Name, + function.Function, + function.Signature..., + ), + ) + } + exprPostEvalOptions = append(exprPostEvalOptions, baseHelpers...) + } + + return exprPostEvalOptions + + /*//FIXME: use expr.Function instead of this return map[string]interface{}{ "IsInBand": request.IsInBand, "IsOutBand": request.IsOutBand, "DumpRequest": request.DumpRequest, - } + }*/ } -func GetOnMatchEnv(w *WaapRuntimeConfig, request *ParsedRequest, evt types.Event) map[string]interface{} { - //FIXME: use expr.Function instead of this +func GetOnMatchEnv(ctx map[string]interface{}, w *WaapRuntimeConfig, request *ParsedRequest) []expr.Option { + baseHelpers := exprhelpers.GetExprOptions(ctx) + onMatchHelpers := []exprhelpers.ExprCustomFunc{ + { + Name: "SetRemediation", + Function: w.SetAction, + Signature: []interface{}{ + new(func(string) error), + }, + }, + { + Name: "SetReturnCode", + Function: w.SetHTTPCode, + Signature: []interface{}{ + new(func(int) error), + }, + }, + { + Name: "CancelEvent", + Function: w.CancelEvent, + Signature: []interface{}{ + new(func() error), + }, + }, + { + Name: "SendEvent", + Function: w.SendEvent, + Signature: []interface{}{ + new(func() error), + }, + }, + { + Name: "CancelAlert", + Function: w.CancelAlert, + Signature: []interface{}{ + new(func() error), + }, + }, + { + Name: "SendAlert", + Function: w.SendAlert, + Signature: []interface{}{ + new(func() error), + }, + }, + { + Name: "DumpRequest", + Function: request.DumpRequest, + Signature: []interface{}{ + new(func() *ReqDumpFilter), + }, + }, + } + + if len(exprOnMatchOptions) == 0 { + for _, function := range onMatchHelpers { + exprOnMatchOptions = append(exprOnMatchOptions, + expr.Function( + function.Name, + function.Function, + function.Signature..., + ), + ) + } + exprOnMatchOptions = append(exprOnMatchOptions, baseHelpers...) + } + + return exprOnMatchOptions + + /*//FIXME: use expr.Function instead of this return map[string]interface{}{ "evt": evt, "req": request, @@ -74,5 +311,5 @@ func GetOnMatchEnv(w *WaapRuntimeConfig, request *ParsedRequest, evt types.Event "CancelAlert": w.CancelAlert, "SendAlert": w.SendAlert, "DumpRequest": request.DumpRequest, - } + }*/ }