2024-01-31 01:59:49 +05:30
package flow
import (
2024-04-03 17:50:57 +02:00
"context"
2024-01-31 01:59:49 +05:30
"reflect"
"sync"
2025-07-09 14:47:26 -05:00
"github.com/Mzack9999/goja"
2024-01-31 01:59:49 +05:30
"github.com/logrusorgru/aurora"
"github.com/projectdiscovery/gologger"
2024-04-01 19:18:21 +05:30
"github.com/projectdiscovery/nuclei/v3/pkg/js/gojs"
2024-01-31 01:59:49 +05:30
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/protocolstate"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/utils/vardump"
"github.com/projectdiscovery/nuclei/v3/pkg/tmplexec/flow/builtin"
"github.com/projectdiscovery/nuclei/v3/pkg/types"
2024-04-03 17:50:57 +02:00
"github.com/projectdiscovery/utils/sync/sizedpool"
2024-01-31 01:59:49 +05:30
)
2024-04-03 17:50:57 +02:00
var jsOnce sync . Once
// js runtime pool using sync.Pool
var gojapool = & sync . Pool {
New : func ( ) interface { } {
runtime := protocolstate . NewJSRuntime ( )
registerBuiltins ( runtime )
return runtime
} ,
2024-01-31 01:59:49 +05:30
}
2024-04-03 17:50:57 +02:00
var sizedgojapool * sizedpool . SizedPool [ * goja . Runtime ]
2024-01-31 01:59:49 +05:30
// GetJSRuntime returns a new JS runtime from pool
func GetJSRuntime ( opts * types . Options ) * goja . Runtime {
2024-04-03 17:50:57 +02:00
jsOnce . Do ( func ( ) {
2024-01-31 01:59:49 +05:30
if opts . JsConcurrency < 100 {
opts . JsConcurrency = 100
}
2025-06-30 15:13:00 +05:30
sizedgojapool , _ = sizedpool . New (
2024-04-03 17:50:57 +02:00
sizedpool . WithPool [ * goja . Runtime ] ( gojapool ) ,
sizedpool . WithSize [ * goja . Runtime ] ( int64 ( opts . JsConcurrency ) ) ,
)
2024-01-31 01:59:49 +05:30
} )
2024-04-03 17:50:57 +02:00
runtime , _ := sizedgojapool . Get ( context . TODO ( ) )
return runtime
2024-01-31 01:59:49 +05:30
}
// PutJSRuntime returns a JS runtime to pool
2025-06-30 15:13:00 +05:30
func PutJSRuntime ( runtime * goja . Runtime , reuse bool ) {
if reuse {
sizedgojapool . Put ( runtime )
} else {
sizedgojapool . Put ( gojapool . Get ( ) . ( * goja . Runtime ) )
}
2024-01-31 01:59:49 +05:30
}
func registerBuiltins ( runtime * goja . Runtime ) {
2024-04-01 19:18:21 +05:30
_ = gojs . RegisterFuncWithSignature ( runtime , gojs . FuncOpts {
Name : "log" ,
Description : "Logs a given object/message to stdout (only for debugging purposes)" ,
Signatures : [ ] string {
"log(obj any) any" ,
} ,
FuncDecl : func ( call goja . FunctionCall ) goja . Value {
arg := call . Argument ( 0 ) . Export ( )
switch value := arg . ( type ) {
case string :
gologger . DefaultLogger . Print ( ) . Msgf ( "[%v] %v" , aurora . BrightCyan ( "JS" ) , value )
case map [ string ] interface { } :
gologger . DefaultLogger . Print ( ) . Msgf ( "[%v] %v" , aurora . BrightCyan ( "JS" ) , vardump . DumpVariables ( value ) )
default :
gologger . DefaultLogger . Print ( ) . Msgf ( "[%v] %v" , aurora . BrightCyan ( "JS" ) , value )
2024-01-31 01:59:49 +05:30
}
2024-04-01 19:18:21 +05:30
return call . Argument ( 0 ) // return the same value
} ,
} )
_ = gojs . RegisterFuncWithSignature ( runtime , gojs . FuncOpts {
Name : "iterate" ,
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" ,
Signatures : [ ] string {
"iterate(...any) []any" ,
} ,
FuncDecl : func ( call goja . FunctionCall ) goja . Value {
allVars := [ ] any { }
for _ , v := range call . Arguments {
if v . Export ( ) == nil {
continue
}
if v . ExportType ( ) . Kind ( ) == reflect . Slice {
// convert []datatype to []interface{}
// since it cannot be type asserted to []interface{} directly
rfValue := reflect . ValueOf ( v . Export ( ) )
for i := 0 ; i < rfValue . Len ( ) ; i ++ {
allVars = append ( allVars , rfValue . Index ( i ) . Interface ( ) )
}
} else {
allVars = append ( allVars , v . Export ( ) )
2024-01-31 01:59:49 +05:30
}
}
2024-04-01 19:18:21 +05:30
return runtime . ToValue ( allVars )
} ,
2024-01-31 01:59:49 +05:30
} )
2024-04-01 19:18:21 +05:30
_ = gojs . RegisterFuncWithSignature ( runtime , gojs . FuncOpts {
Name : "Dedupe" ,
Description : "De-duplicates given values and returns a new array of unique values" ,
Signatures : [ ] string {
"new Dedupe()" ,
} ,
FuncDecl : func ( call goja . ConstructorCall ) * goja . Object {
d := builtin . NewDedupe ( runtime )
obj := call . This
// register these methods
_ = obj . Set ( "Add" , d . Add )
_ = obj . Set ( "Values" , d . Values )
return nil
} ,
2024-01-31 01:59:49 +05:30
} )
2024-04-01 19:18:21 +05:30
2024-01-31 01:59:49 +05:30
}