2020-12-22 03:54:55 +05:30
|
|
|
package dsl
|
2020-05-04 23:24:59 +02:00
|
|
|
|
|
|
|
|
import (
|
2021-11-08 16:24:47 +05:30
|
|
|
"bytes"
|
|
|
|
|
"compress/gzip"
|
2020-05-04 23:24:59 +02:00
|
|
|
"crypto/md5"
|
2020-05-05 21:42:28 +02:00
|
|
|
"crypto/sha1"
|
2020-05-04 23:24:59 +02:00
|
|
|
"crypto/sha256"
|
|
|
|
|
"encoding/base64"
|
|
|
|
|
"encoding/hex"
|
2021-07-23 11:39:30 -07:00
|
|
|
"errors"
|
2020-10-16 14:18:50 +02:00
|
|
|
"fmt"
|
2020-05-04 23:24:59 +02:00
|
|
|
"html"
|
2020-10-11 20:26:27 +02:00
|
|
|
"math"
|
|
|
|
|
"math/rand"
|
2020-05-04 23:24:59 +02:00
|
|
|
"net/url"
|
|
|
|
|
"regexp"
|
2021-12-09 10:32:01 +02:00
|
|
|
"sort"
|
2021-11-26 17:14:25 +02:00
|
|
|
"strconv"
|
2020-05-04 23:24:59 +02:00
|
|
|
"strings"
|
2020-10-23 10:13:34 +02:00
|
|
|
"time"
|
2020-10-16 22:27:25 +02:00
|
|
|
|
2020-05-04 23:24:59 +02:00
|
|
|
"github.com/Knetic/govaluate"
|
2021-12-07 17:34:36 +02:00
|
|
|
"github.com/logrusorgru/aurora"
|
|
|
|
|
"github.com/spaolacci/murmur3"
|
|
|
|
|
|
2021-08-23 19:25:11 +07:00
|
|
|
"github.com/projectdiscovery/gologger"
|
2021-07-18 04:34:39 +05:30
|
|
|
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/helpers/deserialization"
|
2020-12-24 12:13:18 +05:30
|
|
|
"github.com/projectdiscovery/nuclei/v2/pkg/types"
|
2020-05-04 23:24:59 +02:00
|
|
|
)
|
|
|
|
|
|
2020-10-16 22:07:00 +02:00
|
|
|
const (
|
2021-11-26 17:14:25 +02:00
|
|
|
numbers = "1234567890"
|
|
|
|
|
letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
2020-10-16 22:07:00 +02:00
|
|
|
)
|
|
|
|
|
|
2021-11-26 17:14:25 +02:00
|
|
|
var invalidDslFunctionError = errors.New("invalid DSL function signature")
|
2021-12-07 17:34:36 +02:00
|
|
|
var invalidDslFunctionMessageTemplate = "%w. correct method signature %q"
|
2021-09-22 22:41:07 +05:30
|
|
|
|
2021-11-26 17:14:25 +02:00
|
|
|
var dslFunctions map[string]dslFunction
|
2020-08-25 23:24:31 +02:00
|
|
|
|
2021-11-26 17:14:25 +02:00
|
|
|
type dslFunction struct {
|
|
|
|
|
signature string
|
|
|
|
|
expressFunc govaluate.ExpressionFunction
|
|
|
|
|
}
|
2020-08-25 23:24:31 +02:00
|
|
|
|
2021-11-26 17:14:25 +02:00
|
|
|
func init() {
|
|
|
|
|
tempDslFunctions := map[string]func(string) dslFunction{
|
|
|
|
|
"len": makeDslFunction(1, func(args ...interface{}) (interface{}, error) {
|
|
|
|
|
length := len(types.ToString(args[0]))
|
|
|
|
|
return float64(length), nil
|
|
|
|
|
}),
|
2021-12-07 17:34:36 +02:00
|
|
|
"to_upper": makeDslFunction(1, func(args ...interface{}) (interface{}, error) {
|
2021-11-26 17:14:25 +02:00
|
|
|
return strings.ToUpper(types.ToString(args[0])), nil
|
|
|
|
|
}),
|
2021-12-07 17:34:36 +02:00
|
|
|
"to_lower": makeDslFunction(1, func(args ...interface{}) (interface{}, error) {
|
2021-11-26 17:14:25 +02:00
|
|
|
return strings.ToLower(types.ToString(args[0])), nil
|
|
|
|
|
}),
|
2021-12-15 16:03:57 +02:00
|
|
|
"repeat": makeDslFunction(2, func(args ...interface{}) (interface{}, error) {
|
|
|
|
|
count, err := strconv.Atoi(types.ToString(args[1]))
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, invalidDslFunctionError
|
|
|
|
|
}
|
|
|
|
|
return strings.Repeat(types.ToString(args[0]), count), nil
|
|
|
|
|
}),
|
2021-11-26 17:14:25 +02:00
|
|
|
"replace": makeDslFunction(3, func(args ...interface{}) (interface{}, error) {
|
|
|
|
|
return strings.ReplaceAll(types.ToString(args[0]), types.ToString(args[1]), types.ToString(args[2])), nil
|
|
|
|
|
}),
|
|
|
|
|
"replace_regex": makeDslFunction(3, func(args ...interface{}) (interface{}, error) {
|
|
|
|
|
compiled, err := regexp.Compile(types.ToString(args[1]))
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
return compiled.ReplaceAllString(types.ToString(args[0]), types.ToString(args[2])), nil
|
|
|
|
|
}),
|
|
|
|
|
"trim": makeDslFunction(2, func(args ...interface{}) (interface{}, error) {
|
|
|
|
|
return strings.Trim(types.ToString(args[0]), types.ToString(args[1])), nil
|
|
|
|
|
}),
|
2021-12-07 17:34:36 +02:00
|
|
|
"trim_left": makeDslFunction(2, func(args ...interface{}) (interface{}, error) {
|
2021-11-26 17:14:25 +02:00
|
|
|
return strings.TrimLeft(types.ToString(args[0]), types.ToString(args[1])), nil
|
|
|
|
|
}),
|
2021-12-07 17:34:36 +02:00
|
|
|
"trim_right": makeDslFunction(2, func(args ...interface{}) (interface{}, error) {
|
2021-11-26 17:14:25 +02:00
|
|
|
return strings.TrimRight(types.ToString(args[0]), types.ToString(args[1])), nil
|
|
|
|
|
}),
|
2021-12-07 17:34:36 +02:00
|
|
|
"trim_space": makeDslFunction(1, func(args ...interface{}) (interface{}, error) {
|
2021-11-26 17:14:25 +02:00
|
|
|
return strings.TrimSpace(types.ToString(args[0])), nil
|
|
|
|
|
}),
|
2021-12-07 17:34:36 +02:00
|
|
|
"trim_prefix": makeDslFunction(2, func(args ...interface{}) (interface{}, error) {
|
2021-11-26 17:14:25 +02:00
|
|
|
return strings.TrimPrefix(types.ToString(args[0]), types.ToString(args[1])), nil
|
|
|
|
|
}),
|
2021-12-07 17:34:36 +02:00
|
|
|
"trim_suffix": makeDslFunction(2, func(args ...interface{}) (interface{}, error) {
|
2021-11-26 17:14:25 +02:00
|
|
|
return strings.TrimSuffix(types.ToString(args[0]), types.ToString(args[1])), nil
|
|
|
|
|
}),
|
|
|
|
|
"reverse": makeDslFunction(1, func(args ...interface{}) (interface{}, error) {
|
|
|
|
|
return reverseString(types.ToString(args[0])), nil
|
|
|
|
|
}),
|
|
|
|
|
"base64": makeDslFunction(1, func(args ...interface{}) (interface{}, error) {
|
|
|
|
|
return base64.StdEncoding.EncodeToString([]byte(types.ToString(args[0]))), nil
|
|
|
|
|
}),
|
|
|
|
|
"gzip": makeDslFunction(1, func(args ...interface{}) (interface{}, error) {
|
|
|
|
|
buffer := &bytes.Buffer{}
|
|
|
|
|
writer := gzip.NewWriter(buffer)
|
|
|
|
|
if _, err := writer.Write([]byte(args[0].(string))); err != nil {
|
|
|
|
|
return "", err
|
|
|
|
|
}
|
|
|
|
|
_ = writer.Close()
|
2020-10-11 20:26:27 +02:00
|
|
|
|
2021-11-26 17:14:25 +02:00
|
|
|
return buffer.String(), nil
|
|
|
|
|
}),
|
|
|
|
|
"base64_py": makeDslFunction(1, func(args ...interface{}) (interface{}, error) {
|
2021-12-07 17:34:36 +02:00
|
|
|
// python encodes to base64 with lines of 76 bytes terminated by new line "\n"
|
2021-11-26 17:14:25 +02:00
|
|
|
stdBase64 := base64.StdEncoding.EncodeToString([]byte(types.ToString(args[0])))
|
|
|
|
|
return deserialization.InsertInto(stdBase64, 76, '\n'), nil
|
|
|
|
|
}),
|
|
|
|
|
"base64_decode": makeDslFunction(1, func(args ...interface{}) (interface{}, error) {
|
|
|
|
|
return base64.StdEncoding.DecodeString(types.ToString(args[0]))
|
|
|
|
|
}),
|
|
|
|
|
"url_encode": makeDslFunction(1, func(args ...interface{}) (interface{}, error) {
|
|
|
|
|
return url.QueryEscape(types.ToString(args[0])), nil
|
|
|
|
|
}),
|
|
|
|
|
"url_decode": makeDslFunction(1, func(args ...interface{}) (interface{}, error) {
|
|
|
|
|
return url.QueryUnescape(types.ToString(args[0]))
|
|
|
|
|
}),
|
|
|
|
|
"hex_encode": makeDslFunction(1, func(args ...interface{}) (interface{}, error) {
|
|
|
|
|
return hex.EncodeToString([]byte(types.ToString(args[0]))), nil
|
|
|
|
|
}),
|
|
|
|
|
"hex_decode": makeDslFunction(1, func(args ...interface{}) (interface{}, error) {
|
|
|
|
|
decodeString, err := hex.DecodeString(types.ToString(args[0]))
|
|
|
|
|
return decodeString, err
|
|
|
|
|
}),
|
|
|
|
|
"html_escape": makeDslFunction(1, func(args ...interface{}) (interface{}, error) {
|
|
|
|
|
return html.EscapeString(types.ToString(args[0])), nil
|
|
|
|
|
}),
|
|
|
|
|
"html_unescape": makeDslFunction(1, func(args ...interface{}) (interface{}, error) {
|
|
|
|
|
return html.UnescapeString(types.ToString(args[0])), nil
|
|
|
|
|
}),
|
|
|
|
|
"md5": makeDslFunction(1, func(args ...interface{}) (interface{}, error) {
|
|
|
|
|
hash := md5.Sum([]byte(types.ToString(args[0])))
|
|
|
|
|
return hex.EncodeToString(hash[:]), nil
|
|
|
|
|
}),
|
|
|
|
|
"sha256": makeDslFunction(1, func(args ...interface{}) (interface{}, error) {
|
|
|
|
|
hash := sha256.New()
|
|
|
|
|
if _, err := hash.Write([]byte(types.ToString(args[0]))); err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
return hex.EncodeToString(hash.Sum(nil)), nil
|
|
|
|
|
}),
|
|
|
|
|
"sha1": makeDslFunction(1, func(args ...interface{}) (interface{}, error) {
|
|
|
|
|
hash := sha1.New()
|
|
|
|
|
if _, err := hash.Write([]byte(types.ToString(args[0]))); err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
return hex.EncodeToString(hash.Sum(nil)), nil
|
|
|
|
|
}),
|
|
|
|
|
"mmh3": makeDslFunction(1, func(args ...interface{}) (interface{}, error) {
|
|
|
|
|
return fmt.Sprintf("%d", int32(murmur3.Sum32WithSeed([]byte(types.ToString(args[0])), 0))), nil
|
|
|
|
|
}),
|
|
|
|
|
"contains": makeDslFunction(2, func(args ...interface{}) (interface{}, error) {
|
|
|
|
|
return strings.Contains(types.ToString(args[0]), types.ToString(args[1])), nil
|
|
|
|
|
}),
|
|
|
|
|
"regex": makeDslFunction(2, func(args ...interface{}) (interface{}, error) {
|
|
|
|
|
compiled, err := regexp.Compile(types.ToString(args[0]))
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
return compiled.MatchString(types.ToString(args[1])), nil
|
|
|
|
|
}),
|
2021-12-07 17:34:36 +02:00
|
|
|
"remove_bad_chars": makeDslFunction(2, func(args ...interface{}) (interface{}, error) {
|
|
|
|
|
input := types.ToString(args[0])
|
|
|
|
|
badChars := types.ToString(args[1])
|
|
|
|
|
return trimAll(input, badChars), nil
|
|
|
|
|
}),
|
2021-11-26 17:14:25 +02:00
|
|
|
"rand_char": makeDslWithOptionalArgsFunction(
|
2021-12-07 17:34:36 +02:00
|
|
|
"(optionalCharSet string) string",
|
2021-11-26 17:14:25 +02:00
|
|
|
func(args ...interface{}) (interface{}, error) {
|
|
|
|
|
charSet := letters + numbers
|
2020-10-11 20:26:27 +02:00
|
|
|
|
2021-11-26 17:14:25 +02:00
|
|
|
argSize := len(args)
|
2021-12-07 17:34:36 +02:00
|
|
|
if argSize != 0 && argSize != 1 {
|
2021-11-26 17:14:25 +02:00
|
|
|
return nil, invalidDslFunctionError
|
|
|
|
|
}
|
2020-10-11 20:26:27 +02:00
|
|
|
|
2021-11-26 17:14:25 +02:00
|
|
|
if argSize >= 1 {
|
2021-12-15 16:03:57 +02:00
|
|
|
inputCharSet := types.ToString(args[0])
|
|
|
|
|
if strings.TrimSpace(inputCharSet) != "" {
|
|
|
|
|
charSet = inputCharSet
|
|
|
|
|
}
|
2021-11-26 17:14:25 +02:00
|
|
|
}
|
2020-10-11 20:26:27 +02:00
|
|
|
|
2021-12-15 16:03:57 +02:00
|
|
|
return string(charSet[rand.Intn(len(charSet))]), nil
|
2021-11-26 17:14:25 +02:00
|
|
|
},
|
|
|
|
|
),
|
|
|
|
|
"rand_base": makeDslWithOptionalArgsFunction(
|
2021-12-07 17:34:36 +02:00
|
|
|
"(length uint, optionalCharSet string) string",
|
2021-11-26 17:14:25 +02:00
|
|
|
func(args ...interface{}) (interface{}, error) {
|
|
|
|
|
var length int
|
|
|
|
|
charSet := letters + numbers
|
2020-10-11 20:26:27 +02:00
|
|
|
|
2021-11-26 17:14:25 +02:00
|
|
|
argSize := len(args)
|
|
|
|
|
if argSize < 1 || argSize > 3 {
|
|
|
|
|
return nil, invalidDslFunctionError
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
length = int(args[0].(float64))
|
|
|
|
|
|
2021-12-07 17:34:36 +02:00
|
|
|
if argSize == 2 {
|
2021-12-15 16:03:57 +02:00
|
|
|
inputCharSet := types.ToString(args[1])
|
|
|
|
|
if strings.TrimSpace(inputCharSet) != "" {
|
|
|
|
|
charSet = inputCharSet
|
|
|
|
|
}
|
2021-11-26 17:14:25 +02:00
|
|
|
}
|
|
|
|
|
return randSeq(charSet, length), nil
|
|
|
|
|
},
|
|
|
|
|
),
|
|
|
|
|
"rand_text_alphanumeric": makeDslWithOptionalArgsFunction(
|
2021-12-07 17:34:36 +02:00
|
|
|
"(length uint, optionalBadChars string) string",
|
2021-11-26 17:14:25 +02:00
|
|
|
func(args ...interface{}) (interface{}, error) {
|
|
|
|
|
length := 0
|
|
|
|
|
badChars := ""
|
|
|
|
|
|
|
|
|
|
argSize := len(args)
|
|
|
|
|
if argSize != 1 && argSize != 2 {
|
|
|
|
|
return nil, invalidDslFunctionError
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
length = int(args[0].(float64))
|
|
|
|
|
|
|
|
|
|
if argSize == 2 {
|
|
|
|
|
badChars = types.ToString(args[1])
|
|
|
|
|
}
|
|
|
|
|
chars := trimAll(letters+numbers, badChars)
|
|
|
|
|
return randSeq(chars, length), nil
|
|
|
|
|
},
|
|
|
|
|
),
|
|
|
|
|
"rand_text_alpha": makeDslWithOptionalArgsFunction(
|
2021-12-07 17:34:36 +02:00
|
|
|
"(length uint, optionalBadChars string) string",
|
2021-11-26 17:14:25 +02:00
|
|
|
func(args ...interface{}) (interface{}, error) {
|
|
|
|
|
var length int
|
|
|
|
|
badChars := ""
|
|
|
|
|
|
|
|
|
|
argSize := len(args)
|
|
|
|
|
if argSize != 1 && argSize != 2 {
|
|
|
|
|
return nil, invalidDslFunctionError
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
length = int(args[0].(float64))
|
|
|
|
|
|
|
|
|
|
if argSize == 2 {
|
|
|
|
|
badChars = types.ToString(args[1])
|
|
|
|
|
}
|
|
|
|
|
chars := trimAll(letters, badChars)
|
|
|
|
|
return randSeq(chars, length), nil
|
|
|
|
|
},
|
|
|
|
|
),
|
|
|
|
|
"rand_text_numeric": makeDslWithOptionalArgsFunction(
|
2021-12-07 17:34:36 +02:00
|
|
|
"(length uint, optionalBadNumbers string) string",
|
2021-11-26 17:14:25 +02:00
|
|
|
func(args ...interface{}) (interface{}, error) {
|
|
|
|
|
argSize := len(args)
|
|
|
|
|
if argSize != 1 && argSize != 2 {
|
|
|
|
|
return nil, invalidDslFunctionError
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-15 16:03:57 +02:00
|
|
|
length := int(args[0].(float64))
|
2021-12-07 17:34:36 +02:00
|
|
|
badNumbers := ""
|
2021-11-26 17:14:25 +02:00
|
|
|
|
|
|
|
|
if argSize == 2 {
|
|
|
|
|
badNumbers = types.ToString(args[1])
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
chars := trimAll(numbers, badNumbers)
|
|
|
|
|
return randSeq(chars, length), nil
|
|
|
|
|
},
|
|
|
|
|
),
|
|
|
|
|
"rand_int": makeDslWithOptionalArgsFunction(
|
2021-12-07 17:34:36 +02:00
|
|
|
"(optionalMin, optionalMax uint) int",
|
2021-11-26 17:14:25 +02:00
|
|
|
func(args ...interface{}) (interface{}, error) {
|
|
|
|
|
argSize := len(args)
|
2021-12-15 16:03:57 +02:00
|
|
|
if argSize > 2 {
|
2021-11-26 17:14:25 +02:00
|
|
|
return nil, invalidDslFunctionError
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
min := 0
|
|
|
|
|
max := math.MaxInt32
|
|
|
|
|
|
|
|
|
|
if argSize >= 1 {
|
2021-12-15 16:03:57 +02:00
|
|
|
min = int(args[0].(float64))
|
2021-11-26 17:14:25 +02:00
|
|
|
}
|
|
|
|
|
if argSize == 2 {
|
2021-12-15 16:03:57 +02:00
|
|
|
max = int(args[1].(float64))
|
2021-11-26 17:14:25 +02:00
|
|
|
}
|
|
|
|
|
return rand.Intn(max-min) + min, nil
|
|
|
|
|
},
|
|
|
|
|
),
|
|
|
|
|
"generate_java_gadget": makeDslFunction(3, func(args ...interface{}) (interface{}, error) {
|
|
|
|
|
gadget := args[0].(string)
|
|
|
|
|
cmd := args[1].(string)
|
|
|
|
|
encoding := args[2].(string)
|
|
|
|
|
data := deserialization.GenerateJavaGadget(gadget, cmd, encoding)
|
|
|
|
|
return data, nil
|
|
|
|
|
}),
|
2021-12-07 17:34:36 +02:00
|
|
|
"unix_time": makeDslWithOptionalArgsFunction(
|
2021-11-26 17:14:25 +02:00
|
|
|
"(optionalSeconds uint) float64",
|
|
|
|
|
func(args ...interface{}) (interface{}, error) {
|
|
|
|
|
seconds := 0
|
|
|
|
|
|
|
|
|
|
argSize := len(args)
|
|
|
|
|
if argSize != 0 && argSize != 1 {
|
|
|
|
|
return nil, invalidDslFunctionError
|
|
|
|
|
} else if argSize == 1 {
|
2021-12-15 16:03:57 +02:00
|
|
|
seconds = int(args[0].(float64))
|
2021-11-26 17:14:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
offset := time.Now().Add(time.Duration(seconds) * time.Second)
|
|
|
|
|
return float64(offset.Unix()), nil
|
|
|
|
|
},
|
|
|
|
|
),
|
2021-12-07 17:34:36 +02:00
|
|
|
"wait_for": makeDslWithOptionalArgsFunction(
|
2021-11-26 17:14:25 +02:00
|
|
|
"(seconds uint)",
|
|
|
|
|
func(args ...interface{}) (interface{}, error) {
|
|
|
|
|
if len(args) != 1 {
|
|
|
|
|
return nil, invalidDslFunctionError
|
|
|
|
|
}
|
2021-12-15 16:03:57 +02:00
|
|
|
seconds := args[0].(float64)
|
2021-11-26 17:14:25 +02:00
|
|
|
time.Sleep(time.Duration(seconds) * time.Second)
|
|
|
|
|
return true, nil
|
|
|
|
|
},
|
|
|
|
|
),
|
|
|
|
|
"print_debug": makeDslWithOptionalArgsFunction(
|
|
|
|
|
"(args ...interface{})",
|
|
|
|
|
func(args ...interface{}) (interface{}, error) {
|
|
|
|
|
if len(args) < 1 {
|
|
|
|
|
return nil, invalidDslFunctionError
|
|
|
|
|
}
|
|
|
|
|
gologger.Info().Msgf("print_debug value: %s", fmt.Sprint(args))
|
|
|
|
|
return true, nil
|
|
|
|
|
},
|
|
|
|
|
),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dslFunctions = make(map[string]dslFunction, len(tempDslFunctions))
|
|
|
|
|
for funcName, dslFunc := range tempDslFunctions {
|
|
|
|
|
dslFunctions[funcName] = dslFunc(funcName)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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, ", "))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func makeDslWithOptionalArgsFunction(signaturePart string, dslFunctionLogic govaluate.ExpressionFunction) func(functionName string) dslFunction {
|
|
|
|
|
return func(functionName string) dslFunction {
|
|
|
|
|
return dslFunction{
|
|
|
|
|
functionName + signaturePart,
|
|
|
|
|
dslFunctionLogic,
|
2021-09-22 22:41:07 +05:30
|
|
|
}
|
2021-11-26 17:14:25 +02:00
|
|
|
}
|
|
|
|
|
}
|
2021-07-18 05:35:06 +05:30
|
|
|
|
2021-11-26 17:14:25 +02:00
|
|
|
func makeDslFunction(numberOfParameters int, dslFunctionLogic govaluate.ExpressionFunction) func(functionName string) dslFunction {
|
|
|
|
|
return func(functionName string) dslFunction {
|
|
|
|
|
signature := functionName + createSignaturePart(numberOfParameters)
|
|
|
|
|
return dslFunction{
|
|
|
|
|
signature,
|
|
|
|
|
func(args ...interface{}) (interface{}, error) {
|
|
|
|
|
if len(args) != numberOfParameters {
|
2021-12-07 17:34:36 +02:00
|
|
|
return nil, fmt.Errorf(invalidDslFunctionMessageTemplate, invalidDslFunctionError, signature)
|
2021-11-26 17:14:25 +02:00
|
|
|
}
|
|
|
|
|
return dslFunctionLogic(args...)
|
|
|
|
|
},
|
2021-07-18 05:35:06 +05:30
|
|
|
}
|
2021-11-26 17:14:25 +02:00
|
|
|
}
|
2021-07-20 23:27:12 -07:00
|
|
|
}
|
|
|
|
|
|
2021-07-23 11:39:30 -07:00
|
|
|
// HelperFunctions returns the dsl helper functions
|
2021-07-20 23:27:12 -07:00
|
|
|
func HelperFunctions() map[string]govaluate.ExpressionFunction {
|
2021-11-26 17:14:25 +02:00
|
|
|
helperFunctions := make(map[string]govaluate.ExpressionFunction, len(dslFunctions))
|
|
|
|
|
|
|
|
|
|
for functionName, dslFunction := range dslFunctions {
|
|
|
|
|
helperFunctions[functionName] = dslFunction.expressFunc
|
2021-12-07 17:34:36 +02:00
|
|
|
helperFunctions[strings.ReplaceAll(functionName, "_", "")] = dslFunction.expressFunc // for backwards compatibility
|
2021-11-26 17:14:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return helperFunctions
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-07 17:34:36 +02:00
|
|
|
// AddHelperFunction allows creation of additional helper functions to be supported with templates
|
|
|
|
|
//goland:noinspection GoUnusedExportedFunction
|
|
|
|
|
func AddHelperFunction(key string, value func(args ...interface{}) (interface{}, error)) error {
|
|
|
|
|
if _, ok := dslFunctions[key]; !ok {
|
|
|
|
|
dslFunction := dslFunctions[key]
|
|
|
|
|
dslFunction.signature = "(args ...interface{}) interface{}"
|
|
|
|
|
dslFunction.expressFunc = value
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
return errors.New("duplicate helper function key defined")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func GetPrintableDslFunctionSignatures(noColor bool) string {
|
|
|
|
|
aggregateSignatures := func(values []string) string {
|
2021-12-09 10:32:01 +02:00
|
|
|
sort.Strings(values)
|
|
|
|
|
|
2021-12-07 17:34:36 +02:00
|
|
|
builder := &strings.Builder{}
|
|
|
|
|
for _, value := range values {
|
|
|
|
|
builder.WriteRune('\t')
|
|
|
|
|
builder.WriteString(value)
|
|
|
|
|
builder.WriteRune('\n')
|
|
|
|
|
}
|
|
|
|
|
return builder.String()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if noColor {
|
|
|
|
|
return aggregateSignatures(getDslFunctionSignatures())
|
|
|
|
|
}
|
|
|
|
|
return aggregateSignatures(colorizeDslFunctionSignatures())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func getDslFunctionSignatures() []string {
|
2021-11-26 17:14:25 +02:00
|
|
|
result := make([]string, 0, len(dslFunctions))
|
|
|
|
|
|
|
|
|
|
for _, dslFunction := range dslFunctions {
|
|
|
|
|
result = append(result, dslFunction.signature)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result
|
2020-05-04 23:24:59 +02:00
|
|
|
}
|
2020-12-22 03:54:55 +05:30
|
|
|
|
2021-12-07 17:34:36 +02:00
|
|
|
var functionSignaturePattern = regexp.MustCompile(`(\w+)\s*\((?:([\w\d,\s]+)\s+([.\w\d{}&*]+))?\)([\s.\w\d{}&*]+)?`)
|
|
|
|
|
|
|
|
|
|
func colorizeDslFunctionSignatures() []string {
|
|
|
|
|
signatures := getDslFunctionSignatures()
|
|
|
|
|
|
|
|
|
|
colorToOrange := func(value string) string {
|
|
|
|
|
return aurora.Index(208, value).String()
|
2021-07-20 23:27:12 -07:00
|
|
|
}
|
2021-12-07 17:34:36 +02:00
|
|
|
|
|
|
|
|
result := make([]string, 0, len(signatures))
|
|
|
|
|
|
|
|
|
|
for _, signature := range signatures {
|
|
|
|
|
subMatchSlices := functionSignaturePattern.FindAllStringSubmatch(signature, -1)
|
|
|
|
|
if len(subMatchSlices) != 1 {
|
|
|
|
|
// TODO log when #1166 is implemented
|
|
|
|
|
return signatures
|
|
|
|
|
}
|
|
|
|
|
matches := subMatchSlices[0]
|
|
|
|
|
if len(matches) != 5 {
|
|
|
|
|
// TODO log when #1166 is implemented
|
|
|
|
|
return signatures
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
functionParameters := strings.Split(matches[2], ",")
|
|
|
|
|
|
|
|
|
|
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])))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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]))
|
|
|
|
|
|
|
|
|
|
result = append(result, colorizedDslSignature)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result
|
2021-07-20 23:27:12 -07:00
|
|
|
}
|
|
|
|
|
|
2020-12-22 03:54:55 +05:30
|
|
|
func reverseString(s string) string {
|
|
|
|
|
runes := []rune(s)
|
|
|
|
|
for i, j := 0, len(runes)-1; i < j; i, j = i+1, j-1 {
|
|
|
|
|
runes[i], runes[j] = runes[j], runes[i]
|
|
|
|
|
}
|
|
|
|
|
return string(runes)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func trimAll(s, cutset string) string {
|
|
|
|
|
for _, c := range cutset {
|
|
|
|
|
s = strings.ReplaceAll(s, string(c), "")
|
|
|
|
|
}
|
|
|
|
|
return s
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func randSeq(base string, n int) string {
|
|
|
|
|
b := make([]rune, n)
|
|
|
|
|
for i := range b {
|
|
|
|
|
b[i] = rune(base[rand.Intn(len(base))])
|
|
|
|
|
}
|
|
|
|
|
return string(b)
|
|
|
|
|
}
|