Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
projectdiscovery
GitHub Repository: projectdiscovery/nuclei
Path: blob/dev/pkg/tmplexec/flow/vm.go
2070 views
1
package flow
2
3
import (
4
"context"
5
"reflect"
6
"sync"
7
8
"github.com/Mzack9999/goja"
9
"github.com/logrusorgru/aurora"
10
"github.com/projectdiscovery/gologger"
11
"github.com/projectdiscovery/nuclei/v3/pkg/js/gojs"
12
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/protocolstate"
13
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/utils/vardump"
14
"github.com/projectdiscovery/nuclei/v3/pkg/tmplexec/flow/builtin"
15
"github.com/projectdiscovery/nuclei/v3/pkg/types"
16
"github.com/projectdiscovery/utils/sync/sizedpool"
17
)
18
19
var jsOnce sync.Once
20
21
// js runtime pool using sync.Pool
22
var gojapool = &sync.Pool{
23
New: func() interface{} {
24
runtime := protocolstate.NewJSRuntime()
25
registerBuiltins(runtime)
26
return runtime
27
},
28
}
29
30
var sizedgojapool *sizedpool.SizedPool[*goja.Runtime]
31
32
// GetJSRuntime returns a new JS runtime from pool
33
func GetJSRuntime(opts *types.Options) *goja.Runtime {
34
jsOnce.Do(func() {
35
if opts.JsConcurrency < 100 {
36
opts.JsConcurrency = 100
37
}
38
sizedgojapool, _ = sizedpool.New(
39
sizedpool.WithPool[*goja.Runtime](gojapool),
40
sizedpool.WithSize[*goja.Runtime](int64(opts.JsConcurrency)),
41
)
42
})
43
runtime, _ := sizedgojapool.Get(context.TODO())
44
return runtime
45
}
46
47
// PutJSRuntime returns a JS runtime to pool
48
func PutJSRuntime(runtime *goja.Runtime, reuse bool) {
49
if reuse {
50
sizedgojapool.Put(runtime)
51
} else {
52
sizedgojapool.Put(gojapool.Get().(*goja.Runtime))
53
}
54
}
55
56
func registerBuiltins(runtime *goja.Runtime) {
57
_ = gojs.RegisterFuncWithSignature(runtime, gojs.FuncOpts{
58
Name: "log",
59
Description: "Logs a given object/message to stdout (only for debugging purposes)",
60
Signatures: []string{
61
"log(obj any) any",
62
},
63
FuncDecl: func(call goja.FunctionCall) goja.Value {
64
arg := call.Argument(0).Export()
65
switch value := arg.(type) {
66
case string:
67
gologger.DefaultLogger.Print().Msgf("[%v] %v", aurora.BrightCyan("JS"), value)
68
case map[string]interface{}:
69
gologger.DefaultLogger.Print().Msgf("[%v] %v", aurora.BrightCyan("JS"), vardump.DumpVariables(value))
70
default:
71
gologger.DefaultLogger.Print().Msgf("[%v] %v", aurora.BrightCyan("JS"), value)
72
}
73
return call.Argument(0) // return the same value
74
},
75
})
76
77
_ = gojs.RegisterFuncWithSignature(runtime, gojs.FuncOpts{
78
Name: "iterate",
79
Description: "Normalizes and Iterates over all arguments (can be a string,array,null etc) and returns an array of objects\nNote: If the object type is unknown(i.e could be a string or array) iterate should be used and it will always return an array of strings",
80
Signatures: []string{
81
"iterate(...any) []any",
82
},
83
FuncDecl: func(call goja.FunctionCall) goja.Value {
84
allVars := []any{}
85
for _, v := range call.Arguments {
86
if v.Export() == nil {
87
continue
88
}
89
if v.ExportType().Kind() == reflect.Slice {
90
// convert []datatype to []interface{}
91
// since it cannot be type asserted to []interface{} directly
92
rfValue := reflect.ValueOf(v.Export())
93
for i := 0; i < rfValue.Len(); i++ {
94
allVars = append(allVars, rfValue.Index(i).Interface())
95
}
96
} else {
97
allVars = append(allVars, v.Export())
98
}
99
}
100
return runtime.ToValue(allVars)
101
},
102
})
103
104
_ = gojs.RegisterFuncWithSignature(runtime, gojs.FuncOpts{
105
Name: "Dedupe",
106
Description: "De-duplicates given values and returns a new array of unique values",
107
Signatures: []string{
108
"new Dedupe()",
109
},
110
FuncDecl: func(call goja.ConstructorCall) *goja.Object {
111
d := builtin.NewDedupe(runtime)
112
obj := call.This
113
// register these methods
114
_ = obj.Set("Add", d.Add)
115
_ = obj.Set("Values", d.Values)
116
return nil
117
},
118
})
119
120
}
121
122