github.com/projectdiscovery/nuclei/v2@v2.9.15/pkg/protocols/headless/engine/instance.go (about)

     1  package engine
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"time"
     7  
     8  	"github.com/go-rod/rod"
     9  	"github.com/go-rod/rod/lib/utils"
    10  	"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/interactsh"
    11  )
    12  
    13  // Instance is an isolated browser instance opened for doing operations with it.
    14  type Instance struct {
    15  	browser *Browser
    16  	engine  *rod.Browser
    17  
    18  	// redundant due to dependency cycle
    19  	interactsh *interactsh.Client
    20  	requestLog map[string]string // contains actual request that was sent
    21  }
    22  
    23  // NewInstance creates a new instance for the current browser.
    24  //
    25  // The login process is repeated only once for a browser, and the created
    26  // isolated browser instance is used for entire navigation one by one.
    27  //
    28  // Users can also choose to run the login->actions process again
    29  // which uses a new incognito browser instance to run actions.
    30  func (b *Browser) NewInstance() (*Instance, error) {
    31  	browser, err := b.engine.Incognito()
    32  	if err != nil {
    33  		return nil, err
    34  	}
    35  
    36  	// We use a custom sleeper that sleeps from 100ms to 500 ms waiting
    37  	// for an interaction. Used throughout rod for clicking, etc.
    38  	browser = browser.Sleeper(func() utils.Sleeper { return maxBackoffSleeper(10) })
    39  	return &Instance{browser: b, engine: browser, requestLog: map[string]string{}}, nil
    40  }
    41  
    42  // returns a map of [template-defined-urls] -> [actual-request-sent]
    43  // Note: this does not include CORS or other requests while rendering that were not explicitly
    44  // specified in template
    45  func (i *Instance) GetRequestLog() map[string]string {
    46  	return i.requestLog
    47  }
    48  
    49  // Close closes all the tabs and pages for a browser instance
    50  func (i *Instance) Close() error {
    51  	return i.engine.Close()
    52  }
    53  
    54  // SetInteractsh client
    55  func (i *Instance) SetInteractsh(interactsh *interactsh.Client) {
    56  	i.interactsh = interactsh
    57  }
    58  
    59  // maxBackoffSleeper is a backoff sleeper respecting max backoff values
    60  func maxBackoffSleeper(max int) utils.Sleeper {
    61  	count := 0
    62  	backoffSleeper := utils.BackoffSleeper(100*time.Millisecond, 500*time.Millisecond, nil)
    63  
    64  	return func(ctx context.Context) error {
    65  		if ctx.Err() != nil {
    66  			return ctx.Err()
    67  		}
    68  		if count == max {
    69  			return errors.New("max sleep count")
    70  		}
    71  		count++
    72  		return backoffSleeper(ctx)
    73  	}
    74  }