177 lines
4.3 KiB
Go
Raw Normal View History

package contextargs
import (
"context"
"net/http/cookiejar"
"strings"
2023-08-04 20:21:22 +05:30
"sync/atomic"
"github.com/projectdiscovery/gologger"
mapsutil "github.com/projectdiscovery/utils/maps"
sliceutil "github.com/projectdiscovery/utils/slice"
stringsutil "github.com/projectdiscovery/utils/strings"
urlutil "github.com/projectdiscovery/utils/url"
)
var (
// reservedPorts contains list of reserved ports for non-network requests in nuclei
reservedPorts = []string{"80", "443", "8080", "8443", "8081", "53"}
)
// Context implements a shared context struct to share information across multiple templates within a workflow
type Context struct {
ctx context.Context
// Meta is the target for the executor
MetaInput *MetaInput
// CookieJar shared within workflow's http templates
CookieJar *cookiejar.Jar
// Args is a workflow shared key-value store
args *mapsutil.SyncLockMap[string, interface{}]
}
// Create a new contextargs instance
func New(ctx context.Context) *Context {
return NewWithInput(ctx, "")
}
// Create a new contextargs instance with input string
func NewWithInput(ctx context.Context, input string) *Context {
jar, err := cookiejar.New(nil)
if err != nil {
2023-08-04 20:21:22 +05:30
gologger.Error().Msgf("contextargs: could not create cookie jar: %s\n", err)
}
return &Context{
ctx: ctx,
2023-08-04 20:21:22 +05:30
MetaInput: &MetaInput{Input: input},
CookieJar: jar,
args: &mapsutil.SyncLockMap[string, interface{}]{
Map: make(map[string]interface{}),
ReadOnly: atomic.Bool{},
},
}
}
// Context returns the context of the current contextargs
func (ctx *Context) Context() context.Context {
return ctx.ctx
}
// Set the specific key-value pair
func (ctx *Context) Set(key string, value interface{}) {
_ = ctx.args.Set(key, value)
}
func (ctx *Context) hasArgs() bool {
2023-08-04 20:21:22 +05:30
return !ctx.args.IsEmpty()
}
// Merge the key-value pairs
func (ctx *Context) Merge(args map[string]interface{}) {
_ = ctx.args.Merge(args)
}
// Add the specific key-value pair
func (ctx *Context) Add(key string, v interface{}) {
values, ok := ctx.args.Get(key)
if !ok {
ctx.Set(key, v)
}
// If the key exists, append the value to the existing value
switch v := v.(type) {
case []string:
if values, ok := values.([]string); ok {
values = append(values, v...)
ctx.Set(key, values)
}
case string:
if values, ok := values.(string); ok {
tmp := []string{values, v}
ctx.Set(key, tmp)
}
default:
values, _ := ctx.Get(key)
ctx.Set(key, []interface{}{values, v})
}
}
// UseNetworkPort updates input with required/default network port for that template
// but is ignored if input/target contains non-http ports like 80,8080,8081 etc
func (ctx *Context) UseNetworkPort(port string, excludePorts string) error {
ignorePorts := reservedPorts
if excludePorts != "" {
// TODO: add support for service names like http,https,ssh etc once https://github.com/projectdiscovery/netdb is ready
ignorePorts = sliceutil.Dedupe(strings.Split(excludePorts, ","))
}
if port == "" {
// if template does not contain port, do nothing
return nil
}
target, err := urlutil.Parse(ctx.MetaInput.Input)
if err != nil {
return err
}
inputPort := target.Port()
if inputPort == "" || stringsutil.EqualFoldAny(inputPort, ignorePorts...) {
// replace port with networkPort
target.UpdatePort(port)
ctx.MetaInput.Input = target.Host
}
return nil
}
javascript protocol for scripting (includes 15+ proto libs) (#4109) * rebase js-layer PR from @ice3man543 * package restructuring * working * fix duplicated event & matcher status * fix lint error * fix response field * add new functions * multiple minor improvements * fix incorrect stats in js protocol * sort output metadata in cli * remove temp files * remove dead code * add unit and integration test * fix lint error * add jsdoclint using llm * fix error in test * add js lint using llm * generate docs of libs * llm lint * remove duplicated docs * update generated docs * update prompt in doclint * update docs * temp disable version check test * fix unit test and add retry * fix panic in it * update and move jsdocs * updated jsdocs * update docs * update container platform in test * dir restructure and adding docs * add api_reference and remove markdown docs * fix imports * add javascript design and contribution docs * add js protocol documentation * update integration test and docs * update doc ext mdx->md * minor update to docs * new integration test and more * move go libs and add docs * gen new net docs and more * final docs update * add new devtool * use fastdialer * fix build fail * use fastdialer + network sandbox support * add reserved keyword 'Port' * update Port to new syntax * misc update * always enable templatectx in js protocol * move docs to 'js-proto-docs' repo * remove scrapefuncs binary --------- Co-authored-by: sandeep <8293321+ehsandeep@users.noreply.github.com>
2023-09-16 16:02:17 +05:30
// Port returns the port of the target
func (ctx *Context) Port() string {
target, err := urlutil.Parse(ctx.MetaInput.Input)
if err != nil {
return ""
}
return target.Port()
}
// Get the value with specific key if exists
func (ctx *Context) Get(key string) (interface{}, bool) {
if !ctx.hasArgs() {
return nil, false
}
return ctx.args.Get(key)
}
2023-08-04 20:21:22 +05:30
func (ctx *Context) GetAll() map[string]interface{} {
if !ctx.hasArgs() {
return nil
}
2023-08-04 20:21:22 +05:30
return ctx.args.Clone().Map
}
func (ctx *Context) ForEach(f func(string, interface{})) {
_ = ctx.args.Iterate(func(k string, v interface{}) error {
f(k, v)
return nil
})
}
// Has check if the key exists
func (ctx *Context) Has(key string) bool {
return ctx.hasArgs() && ctx.args.Has(key)
}
func (ctx *Context) HasArgs() bool {
return !ctx.args.IsEmpty()
}
func (ctx *Context) Clone() *Context {
newCtx := &Context{
ctx: ctx.ctx,
MetaInput: ctx.MetaInput.Clone(),
args: ctx.args.Clone(),
CookieJar: ctx.CookieJar,
}
return newCtx
}