From 08eb813d5bebc866f8d1a896ee8b4e1bdeea2f74 Mon Sep 17 00:00:00 2001 From: Sajad Parra Date: Thu, 8 Sep 2022 16:19:51 +0530 Subject: [PATCH 1/2] add dsl args validation --- dsl.go | 590 ++++++++++++++++++++++++++++++++++----------------------- go.mod | 1 + go.sum | 2 + 3 files changed, 360 insertions(+), 233 deletions(-) diff --git a/dsl.go b/dsl.go index 082ec59..cdb7459 100644 --- a/dsl.go +++ b/dsl.go @@ -6,15 +6,20 @@ import ( "crypto/sha256" "encoding/base64" "encoding/hex" + "errors" "fmt" "html" "math" "math/rand" "net/url" + "regexp" + "sort" + "strconv" "strings" "time" "github.com/Knetic/govaluate" + "github.com/logrusorgru/aurora" "github.com/spaolacci/murmur3" ) @@ -26,319 +31,438 @@ const ( var letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" var numbers = "1234567890" +var functionSignaturePattern = regexp.MustCompile(`(\w+)\s*\((?:([\w\d,\s]+)\s+([.\w\d{}&*]+))?\)([\s.\w\d{}&*]+)?`) -var DefaultHelperFunctions = HelperFunctions() +var ErrInvalidDslFunction = errors.New("invalid DSL function signature") +var invalidDslFunctionMessageTemplate = "%w. correct method signature %q" -// HelperFunctions contains the dsl functions -func HelperFunctions() (functions map[string]govaluate.ExpressionFunction) { - functions = make(map[string]govaluate.ExpressionFunction) +var dslFunctions map[string]dslFunction +var DefaultHelperFunctions map[string]govaluate.ExpressionFunction - // strings - functions["len"] = func(args ...interface{}) (interface{}, error) { - length := len(toString(args[0])) +type dslFunction struct { + signature string + expressFunc govaluate.ExpressionFunction +} - return float64(length), nil - } +// init initializes the dsl functions +func init() { + tempDslFunctions := map[string]func(string) dslFunction{ + "len": validateDsl(1, func(args ...interface{}) (interface{}, error) { + length := len(toString(args[0])) + return float64(length), nil + }), + "toupper": validateDsl(1, func(args ...interface{}) (interface{}, error) { + return strings.ToUpper(toString(args[0])), nil + }), + + "tolower": validateDsl(1, func(args ...interface{}) (interface{}, error) { + return strings.ToLower(toString(args[0])), nil + }), + + "replace": validateDsl(3, func(args ...interface{}) (interface{}, error) { + return strings.ReplaceAll(toString(args[0]), toString(args[1]), toString(args[2])), nil + }), + + "replace_regex": validateDsl(3, func(args ...interface{}) (interface{}, error) { + compiled, err := Regex(toString(args[1])) + if err != nil { + return nil, err + } + return compiled.ReplaceAllString(toString(args[0]), toString(args[2])), nil + }), - functions["toupper"] = func(args ...interface{}) (interface{}, error) { - return strings.ToUpper(toString(args[0])), nil - } + "trim": validateDsl(2, func(args ...interface{}) (interface{}, error) { + return strings.Trim(toString(args[0]), toString(args[1])), nil + }), - functions["tolower"] = func(args ...interface{}) (interface{}, error) { - return strings.ToLower(toString(args[0])), nil - } + "trimleft": validateDsl(2, func(args ...interface{}) (interface{}, error) { + return strings.TrimLeft(toString(args[0]), toString(args[1])), nil + }), - functions["replace"] = func(args ...interface{}) (interface{}, error) { - return strings.ReplaceAll(toString(args[0]), toString(args[1]), toString(args[2])), nil - } + "trimright": validateDsl(2, func(args ...interface{}) (interface{}, error) { + return strings.TrimRight(toString(args[0]), toString(args[1])), nil + }), - functions["replace_regex"] = func(args ...interface{}) (interface{}, error) { - compiled, err := Regex(toString(args[1])) - if err != nil { - return nil, err - } - return compiled.ReplaceAllString(toString(args[0]), toString(args[2])), nil - } + "trimspace": validateDsl(1, func(args ...interface{}) (interface{}, error) { + return strings.TrimSpace(toString(args[0])), nil + }), - functions["trim"] = func(args ...interface{}) (interface{}, error) { - return strings.Trim(toString(args[0]), toString(args[2])), nil - } + "trimprefix": validateDsl(2, func(args ...interface{}) (interface{}, error) { + return strings.TrimPrefix(toString(args[0]), toString(args[1])), nil + }), - functions["trimleft"] = func(args ...interface{}) (interface{}, error) { - return strings.TrimLeft(toString(args[0]), toString(args[1])), nil - } + "trimsuffix": validateDsl(2, func(args ...interface{}) (interface{}, error) { + return strings.TrimSuffix(toString(args[0]), toString(args[1])), nil + }), - functions["trimright"] = func(args ...interface{}) (interface{}, error) { - return strings.TrimRight(toString(args[0]), toString(args[1])), nil - } + "reverse": validateDsl(1, func(args ...interface{}) (interface{}, error) { + return reverseString(toString(args[0])), nil + }), - functions["trimspace"] = func(args ...interface{}) (interface{}, error) { - return strings.TrimSpace(toString(args[0])), nil - } + // encoding + "base64": validateDsl(1, func(args ...interface{}) (interface{}, error) { + sEnc := base64.StdEncoding.EncodeToString([]byte(toString(args[0]))) - functions["trimprefix"] = func(args ...interface{}) (interface{}, error) { - return strings.TrimPrefix(toString(args[0]), toString(args[1])), nil - } + return sEnc, nil + }), - functions["trimsuffix"] = func(args ...interface{}) (interface{}, error) { - return strings.TrimSuffix(toString(args[0]), toString(args[1])), nil - } + // python encodes to base64 with lines of 76 bytes terminated by new line "\n" + "base64_py": validateDsl(1, func(args ...interface{}) (interface{}, error) { + sEnc := base64.StdEncoding.EncodeToString([]byte(toString(args[0]))) - functions["reverse"] = func(args ...interface{}) (interface{}, error) { - return reverseString(toString(args[0])), nil - } + return insertInto(sEnc, 76, '\n'), nil + }), - // encoding - functions["base64"] = func(args ...interface{}) (interface{}, error) { - sEnc := base64.StdEncoding.EncodeToString([]byte(toString(args[0]))) + "base64_decode": validateDsl(1, func(args ...interface{}) (interface{}, error) { + return base64.StdEncoding.DecodeString(toString(args[0])) + }), - return sEnc, nil - } + "url_encode": validateDsl(1, func(args ...interface{}) (interface{}, error) { + return url.PathEscape(toString(args[0])), nil + }), - // python encodes to base64 with lines of 76 bytes terminated by new line "\n" - functions["base64_py"] = func(args ...interface{}) (interface{}, error) { - sEnc := base64.StdEncoding.EncodeToString([]byte(toString(args[0]))) + "url_decode": validateDsl(1, func(args ...interface{}) (interface{}, error) { + return url.PathUnescape(toString(args[0])) + }), - return insertInto(sEnc, 76, '\n'), nil - } + "hex_encode": validateDsl(1, func(args ...interface{}) (interface{}, error) { + return hex.EncodeToString([]byte(toString(args[0]))), nil + }), - functions["base64_decode"] = func(args ...interface{}) (interface{}, error) { - return base64.StdEncoding.DecodeString(toString(args[0])) - } + "hex_decode": validateDsl(1, func(args ...interface{}) (interface{}, error) { + hx, _ := hex.DecodeString(toString(args[0])) + return string(hx), nil + }), - functions["url_encode"] = func(args ...interface{}) (interface{}, error) { - return url.PathEscape(toString(args[0])), nil - } + "html_escape": validateDsl(1, func(args ...interface{}) (interface{}, error) { + return html.EscapeString(toString(args[0])), nil + }), - functions["url_decode"] = func(args ...interface{}) (interface{}, error) { - return url.PathUnescape(toString(args[0])) - } + "html_unescape": validateDsl(1, func(args ...interface{}) (interface{}, error) { + return html.UnescapeString(toString(args[0])), nil + }), - functions["hex_encode"] = func(args ...interface{}) (interface{}, error) { - return hex.EncodeToString([]byte(toString(args[0]))), nil - } + // hashing + "md5": validateDsl(1, func(args ...interface{}) (interface{}, error) { + hash := md5.Sum([]byte(toString(args[0]))) - functions["hex_decode"] = func(args ...interface{}) (interface{}, error) { - hx, _ := hex.DecodeString(toString(args[0])) - return string(hx), nil - } + return hex.EncodeToString(hash[:]), nil + }), - functions["html_escape"] = func(args ...interface{}) (interface{}, error) { - return html.EscapeString(toString(args[0])), nil - } + "sha256": validateDsl(1, func(args ...interface{}) (interface{}, error) { + h := sha256.New() + _, err := h.Write([]byte(toString(args[0]))) - functions["html_unescape"] = func(args ...interface{}) (interface{}, error) { - return html.UnescapeString(toString(args[0])), nil - } + if err != nil { + return nil, err + } - // hashing - functions["md5"] = func(args ...interface{}) (interface{}, error) { - hash := md5.Sum([]byte(toString(args[0]))) + return hex.EncodeToString(h.Sum(nil)), nil + }), - return hex.EncodeToString(hash[:]), nil - } + "sha1": validateDsl(1, func(args ...interface{}) (interface{}, error) { + h := sha1.New() + _, err := h.Write([]byte(toString(args[0]))) - functions["sha256"] = func(args ...interface{}) (interface{}, error) { - h := sha256.New() - _, err := h.Write([]byte(toString(args[0]))) + if err != nil { + return nil, err + } - if err != nil { - return nil, err - } + return hex.EncodeToString(h.Sum(nil)), nil + }), - return hex.EncodeToString(h.Sum(nil)), nil - } + "mmh3": validateDsl(1, func(args ...interface{}) (interface{}, error) { + return fmt.Sprintf("%d", int32(murmur3.Sum32WithSeed([]byte(toString(args[0])), 0))), nil + }), - functions["sha1"] = func(args ...interface{}) (interface{}, error) { - h := sha1.New() - _, err := h.Write([]byte(toString(args[0]))) + // search + "contains": validateDsl(2, func(args ...interface{}) (interface{}, error) { + return strings.Contains(toString(args[0]), toString(args[1])), nil + }), - if err != nil { - return nil, err - } + "regex": validateDsl(2, func(args ...interface{}) (interface{}, error) { + compiled, err := Regex(toString(args[1])) + if err != nil { + return nil, err + } - return hex.EncodeToString(h.Sum(nil)), nil - } + return compiled.MatchString(toString(args[0])), nil + }), + + "regex_all": validateDsl(2, func(args ...interface{}) (interface{}, error) { + for _, arg := range toSlice(args[1]) { + compiled, err := Regex(toString(arg)) + if err != nil { + return nil, err + } + if !compiled.MatchString(toString(args[0])) { + return false, nil + } + } + return false, nil + }), + + "regex_any": validateDsl(2, func(args ...interface{}) (interface{}, error) { + for _, arg := range toSlice(args[1]) { + compiled, err := Regex(toString(arg)) + if err != nil { + return nil, err + } + if compiled.MatchString(toString(args[0])) { + return true, nil + } + } + return false, nil + }), + + "equals_any": validateDsl(2, func(args ...interface{}) (interface{}, error) { + for _, arg := range toSlice(args[1]) { + if args[0] == arg { + return true, nil + } + } + return false, nil + }), - functions["mmh3"] = func(args ...interface{}) (interface{}, error) { - return fmt.Sprintf("%d", int32(murmur3.Sum32WithSeed([]byte(toString(args[0])), 0))), nil - } + "contains_any": validateDsl(2, func(args ...interface{}) (interface{}, error) { - // search - functions["contains"] = func(args ...interface{}) (interface{}, error) { - return strings.Contains(toString(args[0]), toString(args[1])), nil - } + for _, arg := range toSlice(args[1]) { + if strings.Contains(toString(args[0]), toString(arg)) { + return true, nil + } + } + return false, nil + }), + + "contains_all": validateDsl(2, func(args ...interface{}) (interface{}, error) { + for _, arg := range toSlice(args[1]) { + if !strings.Contains(toString(args[0]), toString(arg)) { + return false, nil + } + } + return true, nil + }), + + // random generators + "rand_char": validateDsl(2, func(args ...interface{}) (interface{}, error) { + chars := letters + numbers + bad := "" + if len(args) >= 1 { + chars = toString(args[0]) + } + if len(args) >= withCutSetArgsSize { + bad = toString(args[1]) + } - functions["regex"] = func(args ...interface{}) (interface{}, error) { - compiled, err := Regex(toString(args[1])) - if err != nil { - return nil, err - } + chars = TrimAll(chars, bad) - return compiled.MatchString(toString(args[0])), nil - } + return chars[rand.Intn(len(chars))], nil + }), - functions["regex_all"] = func(args ...interface{}) (interface{}, error) { - for _, arg := range toSlice(args[1]) { - compiled, err := Regex(toString(arg)) - if err != nil { - return nil, err + "rand_base": validateDsl(3, func(args ...interface{}) (interface{}, error) { + l := 0 + bad := "" + base := letters + numbers + + if len(args) >= 1 { + l = args[0].(int) } - if !compiled.MatchString(toString(args[0])) { - return false, nil + if len(args) >= withCutSetArgsSize { + bad = toString(args[1]) + } + if len(args) >= withBaseRandArgsSize { + base = toString(args[2]) } - } - return false, nil - } - functions["regex_any"] = func(args ...interface{}) (interface{}, error) { - for _, arg := range toSlice(args[1]) { - compiled, err := Regex(toString(arg)) - if err != nil { - return nil, err + base = TrimAll(base, bad) + + return RandSeq(base, l), nil + }), + + "rand_text_alphanumeric": validateDsl(2, func(args ...interface{}) (interface{}, error) { + l := 0 + bad := "" + chars := letters + numbers + + if len(args) >= 1 { + l = args[0].(int) } - if compiled.MatchString(toString(args[0])) { - return true, nil + if len(args) >= withCutSetArgsSize { + bad = toString(args[1]) } - } - return false, nil - } - functions["equals_any"] = func(args ...interface{}) (interface{}, error) { - for _, arg := range toSlice(args[1]) { - if args[0] == arg { - return true, nil + chars = TrimAll(chars, bad) + + return RandSeq(chars, l), nil + }), + + "rand_text_alpha": validateDsl(2, func(args ...interface{}) (interface{}, error) { + l := 0 + bad := "" + chars := letters + + if len(args) >= 1 { + l = args[0].(int) } - } - return false, nil - } + if len(args) >= withCutSetArgsSize { + bad = toString(args[1]) + } + + chars = TrimAll(chars, bad) + + return RandSeq(chars, l), nil + }), - functions["contains_any"] = func(args ...interface{}) (interface{}, error) { + "rand_text_numeric": validateDsl(2, func(args ...interface{}) (interface{}, error) { + l := 0 + bad := "" + chars := numbers - for _, arg := range toSlice(args[1]) { - if strings.Contains(toString(args[0]), toString(arg)) { - return true, nil + if len(args) >= 1 { + l = args[0].(int) + } + if len(args) >= withCutSetArgsSize { + bad = toString(args[1]) } - } - return false, nil - } - functions["contains_all"] = func(args ...interface{}) (interface{}, error) { - for _, arg := range toSlice(args[1]) { - if !strings.Contains(toString(args[0]), toString(arg)) { - return false, nil + chars = TrimAll(chars, bad) + + return RandSeq(chars, l), nil + }), + + "rand_int": validateDsl(2, func(args ...interface{}) (interface{}, error) { + min := 0 + max := math.MaxInt32 + + if len(args) >= 1 { + min = args[0].(int) } - } - return true, nil + if len(args) >= withMaxRandArgsSize { + max = args[1].(int) + } + + return rand.Intn(max-min) + min, nil + }), + + // Time Functions + "waitfor": validateDsl(1, func(args ...interface{}) (interface{}, error) { + seconds := args[0].(float64) + time.Sleep(time.Duration(seconds) * time.Second) + return true, nil + }), } - // random generators - functions["rand_char"] = func(args ...interface{}) (interface{}, error) { - chars := letters + numbers - bad := "" - if len(args) >= 1 { - chars = toString(args[0]) - } - if len(args) >= withCutSetArgsSize { - bad = toString(args[1]) - } + dslFunctions = make(map[string]dslFunction, len(tempDslFunctions)) + for funcName, dslFunc := range tempDslFunctions { + dslFunctions[funcName] = dslFunc(funcName) + } + DefaultHelperFunctions = helperFunctions() +} - chars = TrimAll(chars, bad) +// helperFunctions returns the dsl helper functions +func helperFunctions() map[string]govaluate.ExpressionFunction { + helperFunctions := make(map[string]govaluate.ExpressionFunction, len(dslFunctions)) - return chars[rand.Intn(len(chars))], nil + for functionName, dslFunction := range dslFunctions { + helperFunctions[functionName] = dslFunction.expressFunc + helperFunctions[strings.ReplaceAll(functionName, "_", "")] = dslFunction.expressFunc // for backwards compatibility } - functions["rand_base"] = func(args ...interface{}) (interface{}, error) { - l := 0 - bad := "" - base := letters + numbers + return helperFunctions +} - if len(args) >= 1 { - l = args[0].(int) - } - if len(args) >= withCutSetArgsSize { - bad = toString(args[1]) +func validateDsl(expectedArgsNumber int, dsl govaluate.ExpressionFunction) func(functionName string) dslFunction { + return func(functionName string) dslFunction { + signature := functionName + createSignaturePart(expectedArgsNumber) + return dslFunction{ + signature, + func(args ...interface{}) (interface{}, error) { + if expectedArgsNumber != 0 && len(args) != expectedArgsNumber { + return nil, fmt.Errorf(invalidDslFunctionMessageTemplate, ErrInvalidDslFunction, signature) + + } + return dsl(args...) + }, } - if len(args) >= withBaseRandArgsSize { - base = toString(args[2]) - } - - base = TrimAll(base, bad) + } +} - return RandSeq(base, l), nil +func createSignaturePart(numberOfParameters int) string { + params := make([]string, 0, numberOfParameters) + for i := 1; i <= numberOfParameters; i++ { + params = append(params, "arg"+strconv.Itoa(i)) } + return fmt.Sprintf("(%s interface{}) interface{}", strings.Join(params, ", ")) +} - functions["rand_text_alphanumeric"] = func(args ...interface{}) (interface{}, error) { - l := 0 - bad := "" - chars := letters + numbers +func GetPrintableDslFunctionSignatures(noColor bool) string { + aggregateSignatures := func(values []string) string { + sort.Strings(values) - if len(args) >= 1 { - l = args[0].(int) - } - if len(args) >= withCutSetArgsSize { - bad = toString(args[1]) + builder := &strings.Builder{} + for _, value := range values { + builder.WriteRune('\t') + builder.WriteString(value) + builder.WriteRune('\n') } + return builder.String() + } - chars = TrimAll(chars, bad) - - return RandSeq(chars, l), nil + if noColor { + return aggregateSignatures(getDslFunctionSignatures()) } + return aggregateSignatures(colorizeDslFunctionSignatures()) +} - functions["rand_text_alpha"] = func(args ...interface{}) (interface{}, error) { - l := 0 - bad := "" - chars := letters +func getDslFunctionSignatures() []string { + result := make([]string, 0, len(dslFunctions)) - if len(args) >= 1 { - l = args[0].(int) - } - if len(args) >= withCutSetArgsSize { - bad = toString(args[1]) - } + for _, dslFunction := range dslFunctions { + result = append(result, dslFunction.signature) + } + + return result +} - chars = TrimAll(chars, bad) +func colorizeDslFunctionSignatures() []string { + signatures := getDslFunctionSignatures() - return RandSeq(chars, l), nil + colorToOrange := func(value string) string { + return aurora.Index(208, value).String() } - functions["rand_text_numeric"] = func(args ...interface{}) (interface{}, error) { - l := 0 - bad := "" - chars := numbers + result := make([]string, 0, len(signatures)) - if len(args) >= 1 { - l = args[0].(int) + for _, signature := range signatures { + subMatchSlices := functionSignaturePattern.FindAllStringSubmatch(signature, -1) + if len(subMatchSlices) != 1 { + // TODO log when nuclei#1166 is implemented + return signatures } - if len(args) >= withCutSetArgsSize { - bad = toString(args[1]) + matches := subMatchSlices[0] + if len(matches) != 5 { + // TODO log when nuclei#1166 is implemented + return signatures } - chars = TrimAll(chars, bad) + functionParameters := strings.Split(matches[2], ",") - return RandSeq(chars, l), nil - } - - functions["rand_int"] = func(args ...interface{}) (interface{}, error) { - min := 0 - max := math.MaxInt32 - - if len(args) >= 1 { - min = args[0].(int) - } - if len(args) >= withMaxRandArgsSize { - max = args[1].(int) + var coloredParameterAndTypes []string + for _, functionParameter := range functionParameters { + functionParameter = strings.TrimSpace(functionParameter) + paramAndType := strings.Split(functionParameter, " ") + if len(paramAndType) == 1 { + coloredParameterAndTypes = append(coloredParameterAndTypes, paramAndType[0]) + } else if len(paramAndType) == 2 { + coloredParameterAndTypes = append(coloredParameterAndTypes, fmt.Sprintf("%s %s", paramAndType[0], colorToOrange(paramAndType[1]))) + } } - return rand.Intn(max-min) + min, nil - } + highlightedParams := strings.TrimSpace(fmt.Sprintf("%s %s", strings.Join(coloredParameterAndTypes, ", "), colorToOrange(matches[3]))) + colorizedDslSignature := fmt.Sprintf("%s(%s)%s", aurora.BrightYellow(matches[1]).String(), highlightedParams, colorToOrange(matches[4])) - // Time Functions - functions["waitfor"] = func(args ...interface{}) (interface{}, error) { - seconds := args[0].(float64) - time.Sleep(time.Duration(seconds) * time.Second) - return true, nil + result = append(result, colorizedDslSignature) } - return functions + return result } diff --git a/go.mod b/go.mod index aa4edc8..b860cc8 100644 --- a/go.mod +++ b/go.mod @@ -4,5 +4,6 @@ go 1.14 require ( github.com/Knetic/govaluate v3.0.0+incompatible + github.com/logrusorgru/aurora v2.0.3+incompatible github.com/spaolacci/murmur3 v1.1.0 ) diff --git a/go.sum b/go.sum index 262fca0..e3e11d3 100644 --- a/go.sum +++ b/go.sum @@ -1,4 +1,6 @@ github.com/Knetic/govaluate v3.0.0+incompatible h1:7o6+MAPhYTCF0+fdvoz1xDedhRb4f6s9Tn1Tt7/WTEg= github.com/Knetic/govaluate v3.0.0+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= +github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8= +github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= From cb713da09397cc2605e15957ad414929650e3ae2 Mon Sep 17 00:00:00 2001 From: Sajad Parra Date: Thu, 8 Sep 2022 17:48:47 +0530 Subject: [PATCH 2/2] follow uniform snake case for all dsl functions --- dsl.go | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/dsl.go b/dsl.go index cdb7459..9b0f543 100644 --- a/dsl.go +++ b/dsl.go @@ -51,11 +51,11 @@ func init() { length := len(toString(args[0])) return float64(length), nil }), - "toupper": validateDsl(1, func(args ...interface{}) (interface{}, error) { + "to_upper": validateDsl(1, func(args ...interface{}) (interface{}, error) { return strings.ToUpper(toString(args[0])), nil }), - "tolower": validateDsl(1, func(args ...interface{}) (interface{}, error) { + "to_lower": validateDsl(1, func(args ...interface{}) (interface{}, error) { return strings.ToLower(toString(args[0])), nil }), @@ -75,23 +75,23 @@ func init() { return strings.Trim(toString(args[0]), toString(args[1])), nil }), - "trimleft": validateDsl(2, func(args ...interface{}) (interface{}, error) { + "trim_left": validateDsl(2, func(args ...interface{}) (interface{}, error) { return strings.TrimLeft(toString(args[0]), toString(args[1])), nil }), - "trimright": validateDsl(2, func(args ...interface{}) (interface{}, error) { + "trim_right": validateDsl(2, func(args ...interface{}) (interface{}, error) { return strings.TrimRight(toString(args[0]), toString(args[1])), nil }), - "trimspace": validateDsl(1, func(args ...interface{}) (interface{}, error) { + "trim_space": validateDsl(1, func(args ...interface{}) (interface{}, error) { return strings.TrimSpace(toString(args[0])), nil }), - "trimprefix": validateDsl(2, func(args ...interface{}) (interface{}, error) { + "trim_prefix": validateDsl(2, func(args ...interface{}) (interface{}, error) { return strings.TrimPrefix(toString(args[0]), toString(args[1])), nil }), - "trimsuffix": validateDsl(2, func(args ...interface{}) (interface{}, error) { + "trim_suffix": validateDsl(2, func(args ...interface{}) (interface{}, error) { return strings.TrimSuffix(toString(args[0]), toString(args[1])), nil }), @@ -345,7 +345,7 @@ func init() { }), // Time Functions - "waitfor": validateDsl(1, func(args ...interface{}) (interface{}, error) { + "wait_for": validateDsl(1, func(args ...interface{}) (interface{}, error) { seconds := args[0].(float64) time.Sleep(time.Duration(seconds) * time.Second) return true, nil