mirror of
https://github.com/projectdiscovery/nuclei.git
synced 2025-12-17 20:25:27 +00:00
* feat http response memory optimization + reuse buffers * update nuclei version * feat: reuse js vm's and compile to programs * fix failing http integration test * remove dead code + add -jsc * feat reuse js vms in pool with concurrency * update comments as per review * bug fix+ update interactsh test to look for dns interaction * try enabling all interactsh integration tests --------- Co-authored-by: mzack <marco.rivoli.nvh@gmail.com>
118 lines
3.3 KiB
Go
118 lines
3.3 KiB
Go
// Package compiler provides a compiler for the goja runtime.
|
|
package compiler
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/dop251/goja"
|
|
|
|
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/generators"
|
|
contextutil "github.com/projectdiscovery/utils/context"
|
|
)
|
|
|
|
// Compiler provides a runtime to execute goja runtime
|
|
// based javascript scripts efficiently while also
|
|
// providing them access to custom modules defined in libs/.
|
|
type Compiler struct{}
|
|
|
|
// New creates a new compiler for the goja runtime.
|
|
func New() *Compiler {
|
|
return &Compiler{}
|
|
}
|
|
|
|
// ExecuteOptions provides options for executing a script.
|
|
type ExecuteOptions struct {
|
|
// Callback can be used to register new runtime helper functions
|
|
// ex: export etc
|
|
Callback func(runtime *goja.Runtime) error
|
|
|
|
// Cleanup is extra cleanup function to be called after execution
|
|
Cleanup func(runtime *goja.Runtime)
|
|
|
|
/// Timeout for this script execution
|
|
Timeout int
|
|
}
|
|
|
|
// ExecuteArgs is the arguments to pass to the script.
|
|
type ExecuteArgs struct {
|
|
Args map[string]interface{} //these are protocol variables
|
|
TemplateCtx map[string]interface{} // templateCtx contains template scoped variables
|
|
}
|
|
|
|
// NewExecuteArgs returns a new execute arguments.
|
|
func NewExecuteArgs() *ExecuteArgs {
|
|
return &ExecuteArgs{
|
|
Args: make(map[string]interface{}),
|
|
TemplateCtx: make(map[string]interface{}),
|
|
}
|
|
}
|
|
|
|
// ExecuteResult is the result of executing a script.
|
|
type ExecuteResult map[string]interface{}
|
|
|
|
func NewExecuteResult() ExecuteResult {
|
|
return make(map[string]interface{})
|
|
}
|
|
|
|
// GetSuccess returns whether the script was successful or not.
|
|
func (e ExecuteResult) GetSuccess() bool {
|
|
val, ok := e["success"].(bool)
|
|
if !ok {
|
|
return false
|
|
}
|
|
return val
|
|
}
|
|
|
|
// Execute executes a script with the default options.
|
|
func (c *Compiler) Execute(code string, args *ExecuteArgs) (ExecuteResult, error) {
|
|
p, err := goja.Compile("", code, false)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return c.ExecuteWithOptions(p, args, &ExecuteOptions{})
|
|
}
|
|
|
|
// ExecuteWithOptions executes a script with the provided options.
|
|
func (c *Compiler) ExecuteWithOptions(program *goja.Program, args *ExecuteArgs, opts *ExecuteOptions) (ExecuteResult, error) {
|
|
if opts == nil {
|
|
opts = &ExecuteOptions{}
|
|
}
|
|
if args == nil {
|
|
args = NewExecuteArgs()
|
|
}
|
|
// handle nil maps
|
|
if args.TemplateCtx == nil {
|
|
args.TemplateCtx = make(map[string]interface{})
|
|
}
|
|
if args.Args == nil {
|
|
args.Args = make(map[string]interface{})
|
|
}
|
|
// merge all args into templatectx
|
|
args.TemplateCtx = generators.MergeMaps(args.TemplateCtx, args.Args)
|
|
|
|
if opts.Timeout <= 0 || opts.Timeout > 180 {
|
|
// some js scripts can take longer time so allow configuring timeout
|
|
// from template but keep it within sane limits (180s)
|
|
opts.Timeout = JsProtocolTimeout
|
|
}
|
|
|
|
// execute with context and timeout
|
|
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(opts.Timeout)*time.Second)
|
|
defer cancel()
|
|
// execute the script
|
|
results, err := contextutil.ExecFuncWithTwoReturns(ctx, func() (val goja.Value, err error) {
|
|
defer func() {
|
|
if r := recover(); r != nil {
|
|
err = fmt.Errorf("panic: %v", r)
|
|
}
|
|
}()
|
|
return executeProgram(program, args, opts)
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return ExecuteResult{"response": results.Export(), "success": results.ToBoolean()}, nil
|
|
}
|