mirror of
https://github.com/projectdiscovery/nuclei.git
synced 2025-12-17 22:55:27 +00:00
feat(headless): add ActionWaitDialog type (#5545)
* feat(headless): add `dialog` action type also implement it Signed-off-by: Dwi Siswanto <git@dw1.io> * refactor(headless): add `ActionData` for action output datas Signed-off-by: Dwi Siswanto <git@dw1.io> * refactor(headless): rm `value` arg for `*Page.HandleDialog` also: * expose `err` from \*proto.PageHandleJavaScriptDialog` * conditional ActionData assignment based on Signed-off-by: Dwi Siswanto <git@dw1.io> * refactor(headless): rename to `ActionWaitDialog` Signed-off-by: Dwi Siswanto <git@dw1.io> * test(headless): fix mismatch assertion of `src` output of `ActionGetResource` Signed-off-by: Dwi Siswanto <git@dw1.io> * test(headless): add TestActionWaitDialog test case Signed-off-by: Dwi Siswanto <git@dw1.io> * feat(headless): add `GetActionDataWithDefault` generic func Signed-off-by: Dwi Siswanto <git@dw1.io> * feat(headless): implement `GetActionDataWithDefault` to `header` & `status_code` Signed-off-by: Dwi Siswanto <git@dw1.io> * refactor(headless): use `mapsutil.Map` instead Signed-off-by: Dwi Siswanto <git@dw1.io> * Revert "feat(headless): add `GetActionDataWithDefault` generic func" This reverts commit fa12e0d6a221c8a7bf62200f69814ee27681f08f. --------- Signed-off-by: Dwi Siswanto <git@dw1.io>
This commit is contained in:
parent
9a5272985c
commit
841d8913e5
@ -6,11 +6,15 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/invopop/jsonschema"
|
"github.com/invopop/jsonschema"
|
||||||
|
mapsutil "github.com/projectdiscovery/utils/maps"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ActionType defines the action type for a browser action
|
// ActionType defines the action type for a browser action
|
||||||
type ActionType int8
|
type ActionType int8
|
||||||
|
|
||||||
|
// ActionData stores the action output data
|
||||||
|
type ActionData = mapsutil.Map[string, any]
|
||||||
|
|
||||||
// Types to be executed by the user.
|
// Types to be executed by the user.
|
||||||
// name:ActionType
|
// name:ActionType
|
||||||
const (
|
const (
|
||||||
@ -68,6 +72,9 @@ const (
|
|||||||
// ActionWaitEvent waits for a specific event.
|
// ActionWaitEvent waits for a specific event.
|
||||||
// name:waitevent
|
// name:waitevent
|
||||||
ActionWaitEvent
|
ActionWaitEvent
|
||||||
|
// ActionWaitDialog waits for JavaScript dialog (alert, confirm, prompt, or onbeforeunload).
|
||||||
|
// name:dialog
|
||||||
|
ActionWaitDialog
|
||||||
// ActionKeyboard performs a keyboard action event on a page.
|
// ActionKeyboard performs a keyboard action event on a page.
|
||||||
// name:keyboard
|
// name:keyboard
|
||||||
ActionKeyboard
|
ActionKeyboard
|
||||||
@ -104,6 +111,7 @@ var ActionStringToAction = map[string]ActionType{
|
|||||||
"deleteheader": ActionDeleteHeader,
|
"deleteheader": ActionDeleteHeader,
|
||||||
"setbody": ActionSetBody,
|
"setbody": ActionSetBody,
|
||||||
"waitevent": ActionWaitEvent,
|
"waitevent": ActionWaitEvent,
|
||||||
|
"waitdialog": ActionWaitDialog,
|
||||||
"keyboard": ActionKeyboard,
|
"keyboard": ActionKeyboard,
|
||||||
"debug": ActionDebug,
|
"debug": ActionDebug,
|
||||||
"sleep": ActionSleep,
|
"sleep": ActionSleep,
|
||||||
@ -130,6 +138,7 @@ var ActionToActionString = map[ActionType]string{
|
|||||||
ActionDeleteHeader: "deleteheader",
|
ActionDeleteHeader: "deleteheader",
|
||||||
ActionSetBody: "setbody",
|
ActionSetBody: "setbody",
|
||||||
ActionWaitEvent: "waitevent",
|
ActionWaitEvent: "waitevent",
|
||||||
|
ActionWaitDialog: "waitdialog",
|
||||||
ActionKeyboard: "keyboard",
|
ActionKeyboard: "keyboard",
|
||||||
ActionDebug: "debug",
|
ActionDebug: "debug",
|
||||||
ActionSleep: "sleep",
|
ActionSleep: "sleep",
|
||||||
|
|||||||
@ -45,7 +45,7 @@ type Options struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Run runs a list of actions by creating a new page in the browser.
|
// Run runs a list of actions by creating a new page in the browser.
|
||||||
func (i *Instance) Run(input *contextargs.Context, actions []*Action, payloads map[string]interface{}, options *Options) (map[string]string, *Page, error) {
|
func (i *Instance) Run(input *contextargs.Context, actions []*Action, payloads map[string]interface{}, options *Options) (ActionData, *Page, error) {
|
||||||
page, err := i.engine.Page(proto.TargetCreateTarget{})
|
page, err := i.engine.Page(proto.TargetCreateTarget{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
|
|||||||
@ -48,8 +48,8 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// ExecuteActions executes a list of actions on a page.
|
// ExecuteActions executes a list of actions on a page.
|
||||||
func (p *Page) ExecuteActions(input *contextargs.Context, actions []*Action, variables map[string]interface{}) (outData map[string]string, err error) {
|
func (p *Page) ExecuteActions(input *contextargs.Context, actions []*Action, variables map[string]interface{}) (outData ActionData, err error) {
|
||||||
outData = make(map[string]string)
|
outData = make(ActionData)
|
||||||
// waitFuncs are function that needs to be executed after navigation
|
// waitFuncs are function that needs to be executed after navigation
|
||||||
// typically used for waitEvent
|
// typically used for waitEvent
|
||||||
waitFuncs := make([]func() error, 0)
|
waitFuncs := make([]func() error, 0)
|
||||||
@ -106,6 +106,8 @@ func (p *Page) ExecuteActions(input *contextargs.Context, actions []*Action, var
|
|||||||
if waitFunc != nil {
|
if waitFunc != nil {
|
||||||
waitFuncs = append(waitFuncs, waitFunc)
|
waitFuncs = append(waitFuncs, waitFunc)
|
||||||
}
|
}
|
||||||
|
case ActionWaitDialog:
|
||||||
|
err = p.HandleDialog(act, outData)
|
||||||
case ActionFilesInput:
|
case ActionFilesInput:
|
||||||
if p.options.Options.AllowLocalFileAccess {
|
if p.options.Options.AllowLocalFileAccess {
|
||||||
err = p.FilesInput(act, outData)
|
err = p.FilesInput(act, outData)
|
||||||
@ -148,7 +150,7 @@ type rule struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// WaitVisible waits until an element appears.
|
// WaitVisible waits until an element appears.
|
||||||
func (p *Page) WaitVisible(act *Action, out map[string]string) error {
|
func (p *Page) WaitVisible(act *Action, out ActionData) error {
|
||||||
timeout, err := getTimeout(p, act)
|
timeout, err := getTimeout(p, act)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "Wrong timeout given")
|
return errors.Wrap(err, "Wrong timeout given")
|
||||||
@ -223,7 +225,7 @@ func geTimeParameter(p *Page, act *Action, parameterName string, defaultValue ti
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ActionAddHeader executes a AddHeader action.
|
// ActionAddHeader executes a AddHeader action.
|
||||||
func (p *Page) ActionAddHeader(act *Action, out map[string]string) error {
|
func (p *Page) ActionAddHeader(act *Action, out ActionData) error {
|
||||||
in := p.getActionArgWithDefaultValues(act, "part")
|
in := p.getActionArgWithDefaultValues(act, "part")
|
||||||
|
|
||||||
args := make(map[string]string)
|
args := make(map[string]string)
|
||||||
@ -234,7 +236,7 @@ func (p *Page) ActionAddHeader(act *Action, out map[string]string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ActionSetHeader executes a SetHeader action.
|
// ActionSetHeader executes a SetHeader action.
|
||||||
func (p *Page) ActionSetHeader(act *Action, out map[string]string) error {
|
func (p *Page) ActionSetHeader(act *Action, out ActionData) error {
|
||||||
in := p.getActionArgWithDefaultValues(act, "part")
|
in := p.getActionArgWithDefaultValues(act, "part")
|
||||||
|
|
||||||
args := make(map[string]string)
|
args := make(map[string]string)
|
||||||
@ -245,7 +247,7 @@ func (p *Page) ActionSetHeader(act *Action, out map[string]string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ActionDeleteHeader executes a DeleteHeader action.
|
// ActionDeleteHeader executes a DeleteHeader action.
|
||||||
func (p *Page) ActionDeleteHeader(act *Action, out map[string]string) error {
|
func (p *Page) ActionDeleteHeader(act *Action, out ActionData) error {
|
||||||
in := p.getActionArgWithDefaultValues(act, "part")
|
in := p.getActionArgWithDefaultValues(act, "part")
|
||||||
|
|
||||||
args := make(map[string]string)
|
args := make(map[string]string)
|
||||||
@ -255,7 +257,7 @@ func (p *Page) ActionDeleteHeader(act *Action, out map[string]string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ActionSetBody executes a SetBody action.
|
// ActionSetBody executes a SetBody action.
|
||||||
func (p *Page) ActionSetBody(act *Action, out map[string]string) error {
|
func (p *Page) ActionSetBody(act *Action, out ActionData) error {
|
||||||
in := p.getActionArgWithDefaultValues(act, "part")
|
in := p.getActionArgWithDefaultValues(act, "part")
|
||||||
|
|
||||||
args := make(map[string]string)
|
args := make(map[string]string)
|
||||||
@ -265,7 +267,7 @@ func (p *Page) ActionSetBody(act *Action, out map[string]string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ActionSetMethod executes an SetMethod action.
|
// ActionSetMethod executes an SetMethod action.
|
||||||
func (p *Page) ActionSetMethod(act *Action, out map[string]string) error {
|
func (p *Page) ActionSetMethod(act *Action, out ActionData) error {
|
||||||
in := p.getActionArgWithDefaultValues(act, "part")
|
in := p.getActionArgWithDefaultValues(act, "part")
|
||||||
|
|
||||||
args := make(map[string]string)
|
args := make(map[string]string)
|
||||||
@ -275,7 +277,7 @@ func (p *Page) ActionSetMethod(act *Action, out map[string]string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NavigateURL executes an ActionLoadURL actions loading a URL for the page.
|
// NavigateURL executes an ActionLoadURL actions loading a URL for the page.
|
||||||
func (p *Page) NavigateURL(action *Action, out map[string]string, allvars map[string]interface{}) error {
|
func (p *Page) NavigateURL(action *Action, out ActionData, allvars map[string]interface{}) error {
|
||||||
// input <- is input url from cli
|
// input <- is input url from cli
|
||||||
// target <- is the url from template (ex: {{BaseURL}}/test)
|
// target <- is the url from template (ex: {{BaseURL}}/test)
|
||||||
input, err := urlutil.Parse(p.input.MetaInput.Input)
|
input, err := urlutil.Parse(p.input.MetaInput.Input)
|
||||||
@ -331,7 +333,7 @@ func (p *Page) NavigateURL(action *Action, out map[string]string, allvars map[st
|
|||||||
}
|
}
|
||||||
|
|
||||||
// RunScript runs a script on the loaded page
|
// RunScript runs a script on the loaded page
|
||||||
func (p *Page) RunScript(action *Action, out map[string]string) error {
|
func (p *Page) RunScript(action *Action, out ActionData) error {
|
||||||
code := p.getActionArgWithDefaultValues(action, "code")
|
code := p.getActionArgWithDefaultValues(action, "code")
|
||||||
if code == "" {
|
if code == "" {
|
||||||
return errinvalidArguments
|
return errinvalidArguments
|
||||||
@ -352,7 +354,7 @@ func (p *Page) RunScript(action *Action, out map[string]string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ClickElement executes click actions for an element.
|
// ClickElement executes click actions for an element.
|
||||||
func (p *Page) ClickElement(act *Action, out map[string]string) error {
|
func (p *Page) ClickElement(act *Action, out ActionData) error {
|
||||||
element, err := p.pageElementBy(act.Data)
|
element, err := p.pageElementBy(act.Data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, errCouldNotGetElement)
|
return errors.Wrap(err, errCouldNotGetElement)
|
||||||
@ -367,12 +369,12 @@ func (p *Page) ClickElement(act *Action, out map[string]string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// KeyboardAction executes a keyboard action on the page.
|
// KeyboardAction executes a keyboard action on the page.
|
||||||
func (p *Page) KeyboardAction(act *Action, out map[string]string) error {
|
func (p *Page) KeyboardAction(act *Action, out ActionData) error {
|
||||||
return p.page.Keyboard.Type([]input.Key(p.getActionArgWithDefaultValues(act, "keys"))...)
|
return p.page.Keyboard.Type([]input.Key(p.getActionArgWithDefaultValues(act, "keys"))...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// RightClickElement executes right click actions for an element.
|
// RightClickElement executes right click actions for an element.
|
||||||
func (p *Page) RightClickElement(act *Action, out map[string]string) error {
|
func (p *Page) RightClickElement(act *Action, out ActionData) error {
|
||||||
element, err := p.pageElementBy(act.Data)
|
element, err := p.pageElementBy(act.Data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, errCouldNotGetElement)
|
return errors.Wrap(err, errCouldNotGetElement)
|
||||||
@ -387,7 +389,7 @@ func (p *Page) RightClickElement(act *Action, out map[string]string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Screenshot executes screenshot action on a page
|
// Screenshot executes screenshot action on a page
|
||||||
func (p *Page) Screenshot(act *Action, out map[string]string) error {
|
func (p *Page) Screenshot(act *Action, out ActionData) error {
|
||||||
to := p.getActionArgWithDefaultValues(act, "to")
|
to := p.getActionArgWithDefaultValues(act, "to")
|
||||||
if to == "" {
|
if to == "" {
|
||||||
to = ksuid.New().String()
|
to = ksuid.New().String()
|
||||||
@ -450,7 +452,7 @@ func (p *Page) Screenshot(act *Action, out map[string]string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// InputElement executes input element actions for an element.
|
// InputElement executes input element actions for an element.
|
||||||
func (p *Page) InputElement(act *Action, out map[string]string) error {
|
func (p *Page) InputElement(act *Action, out ActionData) error {
|
||||||
value := p.getActionArgWithDefaultValues(act, "value")
|
value := p.getActionArgWithDefaultValues(act, "value")
|
||||||
if value == "" {
|
if value == "" {
|
||||||
return errinvalidArguments
|
return errinvalidArguments
|
||||||
@ -469,7 +471,7 @@ func (p *Page) InputElement(act *Action, out map[string]string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TimeInputElement executes time input on an element
|
// TimeInputElement executes time input on an element
|
||||||
func (p *Page) TimeInputElement(act *Action, out map[string]string) error {
|
func (p *Page) TimeInputElement(act *Action, out ActionData) error {
|
||||||
value := p.getActionArgWithDefaultValues(act, "value")
|
value := p.getActionArgWithDefaultValues(act, "value")
|
||||||
if value == "" {
|
if value == "" {
|
||||||
return errinvalidArguments
|
return errinvalidArguments
|
||||||
@ -492,7 +494,7 @@ func (p *Page) TimeInputElement(act *Action, out map[string]string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SelectInputElement executes select input statement action on a element
|
// SelectInputElement executes select input statement action on a element
|
||||||
func (p *Page) SelectInputElement(act *Action, out map[string]string) error {
|
func (p *Page) SelectInputElement(act *Action, out ActionData) error {
|
||||||
value := p.getActionArgWithDefaultValues(act, "value")
|
value := p.getActionArgWithDefaultValues(act, "value")
|
||||||
if value == "" {
|
if value == "" {
|
||||||
return errinvalidArguments
|
return errinvalidArguments
|
||||||
@ -517,7 +519,7 @@ func (p *Page) SelectInputElement(act *Action, out map[string]string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// WaitLoad waits for the page to load
|
// WaitLoad waits for the page to load
|
||||||
func (p *Page) WaitLoad(act *Action, out map[string]string) error {
|
func (p *Page) WaitLoad(act *Action, out ActionData) error {
|
||||||
p.page.Timeout(2 * time.Second).WaitNavigation(proto.PageLifecycleEventNameFirstMeaningfulPaint)()
|
p.page.Timeout(2 * time.Second).WaitNavigation(proto.PageLifecycleEventNameFirstMeaningfulPaint)()
|
||||||
|
|
||||||
// Wait for the window.onload event and also wait for the network requests
|
// Wait for the window.onload event and also wait for the network requests
|
||||||
@ -531,7 +533,7 @@ func (p *Page) WaitLoad(act *Action, out map[string]string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetResource gets a resource from an element from page.
|
// GetResource gets a resource from an element from page.
|
||||||
func (p *Page) GetResource(act *Action, out map[string]string) error {
|
func (p *Page) GetResource(act *Action, out ActionData) error {
|
||||||
element, err := p.pageElementBy(act.Data)
|
element, err := p.pageElementBy(act.Data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, errCouldNotGetElement)
|
return errors.Wrap(err, errCouldNotGetElement)
|
||||||
@ -547,7 +549,7 @@ func (p *Page) GetResource(act *Action, out map[string]string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// FilesInput acts with a file input element on page
|
// FilesInput acts with a file input element on page
|
||||||
func (p *Page) FilesInput(act *Action, out map[string]string) error {
|
func (p *Page) FilesInput(act *Action, out ActionData) error {
|
||||||
element, err := p.pageElementBy(act.Data)
|
element, err := p.pageElementBy(act.Data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, errCouldNotGetElement)
|
return errors.Wrap(err, errCouldNotGetElement)
|
||||||
@ -564,7 +566,7 @@ func (p *Page) FilesInput(act *Action, out map[string]string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ExtractElement extracts from an element on the page.
|
// ExtractElement extracts from an element on the page.
|
||||||
func (p *Page) ExtractElement(act *Action, out map[string]string) error {
|
func (p *Page) ExtractElement(act *Action, out ActionData) error {
|
||||||
element, err := p.pageElementBy(act.Data)
|
element, err := p.pageElementBy(act.Data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, errCouldNotGetElement)
|
return errors.Wrap(err, errCouldNotGetElement)
|
||||||
@ -598,7 +600,7 @@ func (p *Page) ExtractElement(act *Action, out map[string]string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// WaitEvent waits for an event to happen on the page.
|
// WaitEvent waits for an event to happen on the page.
|
||||||
func (p *Page) WaitEvent(act *Action, out map[string]string) (func() error, error) {
|
func (p *Page) WaitEvent(act *Action, out ActionData) (func() error, error) {
|
||||||
event := p.getActionArgWithDefaultValues(act, "event")
|
event := p.getActionArgWithDefaultValues(act, "event")
|
||||||
if event == "" {
|
if event == "" {
|
||||||
return nil, errors.New("event not recognized")
|
return nil, errors.New("event not recognized")
|
||||||
@ -636,6 +638,43 @@ func (p *Page) WaitEvent(act *Action, out map[string]string) (func() error, erro
|
|||||||
return waitFunc, nil
|
return waitFunc, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HandleDialog handles JavaScript dialog (alert, confirm, prompt, or onbeforeunload).
|
||||||
|
func (p *Page) HandleDialog(act *Action, out ActionData) error {
|
||||||
|
maxDuration := 10 * time.Second
|
||||||
|
|
||||||
|
if dur := p.getActionArgWithDefaultValues(act, "max-duration"); dur != "" {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
maxDuration, err = time.ParseDuration(dur)
|
||||||
|
if err != nil {
|
||||||
|
return errorutil.NewWithErr(err).Msgf("could not parse max-duration")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), maxDuration)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
wait, handle := p.page.HandleDialog()
|
||||||
|
fn := func() (*proto.PageJavascriptDialogOpening, error) {
|
||||||
|
dialog := wait()
|
||||||
|
err := handle(&proto.PageHandleJavaScriptDialog{
|
||||||
|
Accept: true,
|
||||||
|
PromptText: "",
|
||||||
|
})
|
||||||
|
|
||||||
|
return dialog, err
|
||||||
|
}
|
||||||
|
|
||||||
|
dialog, err := contextutil.ExecFuncWithTwoReturns(ctx, fn)
|
||||||
|
if err == nil && act.Name != "" {
|
||||||
|
out[act.Name] = true
|
||||||
|
out[act.Name+"_type"] = string(dialog.Type)
|
||||||
|
out[act.Name+"_message"] = dialog.Message
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// pageElementBy returns a page element from a variety of inputs.
|
// pageElementBy returns a page element from a variety of inputs.
|
||||||
//
|
//
|
||||||
// Supported values for by: r -> selector & regex, x -> xpath, js -> eval js,
|
// Supported values for by: r -> selector & regex, x -> xpath, js -> eval js,
|
||||||
@ -670,14 +709,14 @@ func (p *Page) pageElementBy(data map[string]string) (*rod.Element, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// DebugAction enables debug action on a page.
|
// DebugAction enables debug action on a page.
|
||||||
func (p *Page) DebugAction(act *Action, out map[string]string) error {
|
func (p *Page) DebugAction(act *Action, out ActionData) error {
|
||||||
p.instance.browser.engine.SlowMotion(5 * time.Second)
|
p.instance.browser.engine.SlowMotion(5 * time.Second)
|
||||||
p.instance.browser.engine.Trace(true)
|
p.instance.browser.engine.Trace(true)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SleepAction sleeps on the page for a specified duration
|
// SleepAction sleeps on the page for a specified duration
|
||||||
func (p *Page) SleepAction(act *Action, out map[string]string) error {
|
func (p *Page) SleepAction(act *Action, out ActionData) error {
|
||||||
seconds := act.Data["duration"]
|
seconds := act.Data["duration"]
|
||||||
if seconds == "" {
|
if seconds == "" {
|
||||||
seconds = "5"
|
seconds = "5"
|
||||||
|
|||||||
@ -38,7 +38,7 @@ func TestActionNavigate(t *testing.T) {
|
|||||||
|
|
||||||
actions := []*Action{{ActionType: ActionTypeHolder{ActionType: ActionNavigate}, Data: map[string]string{"url": "{{BaseURL}}"}}, {ActionType: ActionTypeHolder{ActionType: ActionWaitLoad}}}
|
actions := []*Action{{ActionType: ActionTypeHolder{ActionType: ActionNavigate}, Data: map[string]string{"url": "{{BaseURL}}"}}, {ActionType: ActionTypeHolder{ActionType: ActionWaitLoad}}}
|
||||||
|
|
||||||
testHeadlessSimpleResponse(t, response, actions, 20*time.Second, func(page *Page, err error, out map[string]string) {
|
testHeadlessSimpleResponse(t, response, actions, 20*time.Second, func(page *Page, err error, out ActionData) {
|
||||||
require.Nilf(t, err, "could not run page actions")
|
require.Nilf(t, err, "could not run page actions")
|
||||||
require.Equal(t, "Nuclei Test Page", page.Page().MustInfo().Title, "could not navigate correctly")
|
require.Equal(t, "Nuclei Test Page", page.Page().MustInfo().Title, "could not navigate correctly")
|
||||||
})
|
})
|
||||||
@ -63,7 +63,7 @@ func TestActionScript(t *testing.T) {
|
|||||||
{ActionType: ActionTypeHolder{ActionType: ActionScript}, Name: "test", Data: map[string]string{"code": "() => window.test"}},
|
{ActionType: ActionTypeHolder{ActionType: ActionScript}, Name: "test", Data: map[string]string{"code": "() => window.test"}},
|
||||||
}
|
}
|
||||||
|
|
||||||
testHeadlessSimpleResponse(t, response, actions, timeout, func(page *Page, err error, out map[string]string) {
|
testHeadlessSimpleResponse(t, response, actions, timeout, func(page *Page, err error, out ActionData) {
|
||||||
require.Nil(t, err, "could not run page actions")
|
require.Nil(t, err, "could not run page actions")
|
||||||
require.Equal(t, "Nuclei Test Page", page.Page().MustInfo().Title, "could not navigate correctly")
|
require.Equal(t, "Nuclei Test Page", page.Page().MustInfo().Title, "could not navigate correctly")
|
||||||
require.Equal(t, "some-data", out["test"], "could not run js and get results correctly")
|
require.Equal(t, "some-data", out["test"], "could not run js and get results correctly")
|
||||||
@ -77,7 +77,7 @@ func TestActionScript(t *testing.T) {
|
|||||||
{ActionType: ActionTypeHolder{ActionType: ActionWaitLoad}},
|
{ActionType: ActionTypeHolder{ActionType: ActionWaitLoad}},
|
||||||
{ActionType: ActionTypeHolder{ActionType: ActionScript}, Name: "test", Data: map[string]string{"code": "() => window.test"}},
|
{ActionType: ActionTypeHolder{ActionType: ActionScript}, Name: "test", Data: map[string]string{"code": "() => window.test"}},
|
||||||
}
|
}
|
||||||
testHeadlessSimpleResponse(t, response, actions, timeout, func(page *Page, err error, out map[string]string) {
|
testHeadlessSimpleResponse(t, response, actions, timeout, func(page *Page, err error, out ActionData) {
|
||||||
require.Nil(t, err, "could not run page actions")
|
require.Nil(t, err, "could not run page actions")
|
||||||
require.Equal(t, "Nuclei Test Page", page.Page().MustInfo().Title, "could not navigate correctly")
|
require.Equal(t, "Nuclei Test Page", page.Page().MustInfo().Title, "could not navigate correctly")
|
||||||
require.Equal(t, "some-data", out["test"], "could not run js and get results correctly with js hook")
|
require.Equal(t, "some-data", out["test"], "could not run js and get results correctly with js hook")
|
||||||
@ -101,7 +101,7 @@ func TestActionClick(t *testing.T) {
|
|||||||
{ActionType: ActionTypeHolder{ActionType: ActionClick}, Data: map[string]string{"selector": "button"}}, // Use css selector for clicking
|
{ActionType: ActionTypeHolder{ActionType: ActionClick}, Data: map[string]string{"selector": "button"}}, // Use css selector for clicking
|
||||||
}
|
}
|
||||||
|
|
||||||
testHeadlessSimpleResponse(t, response, actions, 20*time.Second, func(page *Page, err error, out map[string]string) {
|
testHeadlessSimpleResponse(t, response, actions, 20*time.Second, func(page *Page, err error, out ActionData) {
|
||||||
require.Nil(t, err, "could not run page actions")
|
require.Nil(t, err, "could not run page actions")
|
||||||
require.Equal(t, "Nuclei Test Page", page.Page().MustInfo().Title, "could not navigate correctly")
|
require.Equal(t, "Nuclei Test Page", page.Page().MustInfo().Title, "could not navigate correctly")
|
||||||
el := page.Page().MustElement("button")
|
el := page.Page().MustElement("button")
|
||||||
@ -134,7 +134,7 @@ func TestActionRightClick(t *testing.T) {
|
|||||||
{ActionType: ActionTypeHolder{ActionType: ActionRightClick}, Data: map[string]string{"selector": "button"}}, // Use css selector for clicking
|
{ActionType: ActionTypeHolder{ActionType: ActionRightClick}, Data: map[string]string{"selector": "button"}}, // Use css selector for clicking
|
||||||
}
|
}
|
||||||
|
|
||||||
testHeadlessSimpleResponse(t, response, actions, 20*time.Second, func(page *Page, err error, out map[string]string) {
|
testHeadlessSimpleResponse(t, response, actions, 20*time.Second, func(page *Page, err error, out ActionData) {
|
||||||
require.Nil(t, err, "could not run page actions")
|
require.Nil(t, err, "could not run page actions")
|
||||||
require.Equal(t, "Nuclei Test Page", page.Page().MustInfo().Title, "could not navigate correctly")
|
require.Equal(t, "Nuclei Test Page", page.Page().MustInfo().Title, "could not navigate correctly")
|
||||||
el := page.Page().MustElement("button")
|
el := page.Page().MustElement("button")
|
||||||
@ -159,7 +159,7 @@ func TestActionTextInput(t *testing.T) {
|
|||||||
{ActionType: ActionTypeHolder{ActionType: ActionTextInput}, Data: map[string]string{"selector": "input", "value": "test"}},
|
{ActionType: ActionTypeHolder{ActionType: ActionTextInput}, Data: map[string]string{"selector": "input", "value": "test"}},
|
||||||
}
|
}
|
||||||
|
|
||||||
testHeadlessSimpleResponse(t, response, actions, 20*time.Second, func(page *Page, err error, out map[string]string) {
|
testHeadlessSimpleResponse(t, response, actions, 20*time.Second, func(page *Page, err error, out ActionData) {
|
||||||
require.Nil(t, err, "could not run page actions")
|
require.Nil(t, err, "could not run page actions")
|
||||||
require.Equal(t, "Nuclei Test Page", page.Page().MustInfo().Title, "could not navigate correctly")
|
require.Equal(t, "Nuclei Test Page", page.Page().MustInfo().Title, "could not navigate correctly")
|
||||||
el := page.Page().MustElement("input")
|
el := page.Page().MustElement("input")
|
||||||
@ -182,7 +182,7 @@ func TestActionHeadersChange(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
testHeadless(t, actions, 20*time.Second, handler, func(page *Page, err error, out map[string]string) {
|
testHeadless(t, actions, 20*time.Second, handler, func(page *Page, err error, out ActionData) {
|
||||||
require.Nil(t, err, "could not run page actions")
|
require.Nil(t, err, "could not run page actions")
|
||||||
require.Equal(t, "found", strings.ToLower(strings.TrimSpace(page.Page().MustElement("html").MustText())), "could not set header correctly")
|
require.Equal(t, "found", strings.ToLower(strings.TrimSpace(page.Page().MustElement("html").MustText())), "could not set header correctly")
|
||||||
})
|
})
|
||||||
@ -205,7 +205,7 @@ func TestActionScreenshot(t *testing.T) {
|
|||||||
{ActionType: ActionTypeHolder{ActionType: ActionScreenshot}, Data: map[string]string{"to": filePath}},
|
{ActionType: ActionTypeHolder{ActionType: ActionScreenshot}, Data: map[string]string{"to": filePath}},
|
||||||
}
|
}
|
||||||
|
|
||||||
testHeadlessSimpleResponse(t, response, actions, 20*time.Second, func(page *Page, err error, out map[string]string) {
|
testHeadlessSimpleResponse(t, response, actions, 20*time.Second, func(page *Page, err error, out ActionData) {
|
||||||
require.Nil(t, err, "could not run page actions")
|
require.Nil(t, err, "could not run page actions")
|
||||||
require.Equal(t, "Nuclei Test Page", page.Page().MustInfo().Title, "could not navigate correctly")
|
require.Equal(t, "Nuclei Test Page", page.Page().MustInfo().Title, "could not navigate correctly")
|
||||||
_ = page.Page()
|
_ = page.Page()
|
||||||
@ -233,7 +233,7 @@ func TestActionScreenshotToDir(t *testing.T) {
|
|||||||
{ActionType: ActionTypeHolder{ActionType: ActionScreenshot}, Data: map[string]string{"to": filePath, "mkdir": "true"}},
|
{ActionType: ActionTypeHolder{ActionType: ActionScreenshot}, Data: map[string]string{"to": filePath, "mkdir": "true"}},
|
||||||
}
|
}
|
||||||
|
|
||||||
testHeadlessSimpleResponse(t, response, actions, 20*time.Second, func(page *Page, err error, out map[string]string) {
|
testHeadlessSimpleResponse(t, response, actions, 20*time.Second, func(page *Page, err error, out ActionData) {
|
||||||
require.Nil(t, err, "could not run page actions")
|
require.Nil(t, err, "could not run page actions")
|
||||||
require.Equal(t, "Nuclei Test Page", page.Page().MustInfo().Title, "could not navigate correctly")
|
require.Equal(t, "Nuclei Test Page", page.Page().MustInfo().Title, "could not navigate correctly")
|
||||||
_ = page.Page()
|
_ = page.Page()
|
||||||
@ -260,7 +260,7 @@ func TestActionTimeInput(t *testing.T) {
|
|||||||
{ActionType: ActionTypeHolder{ActionType: ActionTimeInput}, Data: map[string]string{"selector": "input", "value": "2006-01-02T15:04:05Z"}},
|
{ActionType: ActionTypeHolder{ActionType: ActionTimeInput}, Data: map[string]string{"selector": "input", "value": "2006-01-02T15:04:05Z"}},
|
||||||
}
|
}
|
||||||
|
|
||||||
testHeadlessSimpleResponse(t, response, actions, 20*time.Second, func(page *Page, err error, out map[string]string) {
|
testHeadlessSimpleResponse(t, response, actions, 20*time.Second, func(page *Page, err error, out ActionData) {
|
||||||
require.Nil(t, err, "could not run page actions")
|
require.Nil(t, err, "could not run page actions")
|
||||||
require.Equal(t, "Nuclei Test Page", page.Page().MustInfo().Title, "could not navigate correctly")
|
require.Equal(t, "Nuclei Test Page", page.Page().MustInfo().Title, "could not navigate correctly")
|
||||||
el := page.Page().MustElement("input")
|
el := page.Page().MustElement("input")
|
||||||
@ -288,7 +288,7 @@ func TestActionSelectInput(t *testing.T) {
|
|||||||
{ActionType: ActionTypeHolder{ActionType: ActionSelectInput}, Data: map[string]string{"by": "x", "xpath": "//select[@id='test']", "value": "Test2", "selected": "true"}},
|
{ActionType: ActionTypeHolder{ActionType: ActionSelectInput}, Data: map[string]string{"by": "x", "xpath": "//select[@id='test']", "value": "Test2", "selected": "true"}},
|
||||||
}
|
}
|
||||||
|
|
||||||
testHeadlessSimpleResponse(t, response, actions, 20*time.Second, func(page *Page, err error, out map[string]string) {
|
testHeadlessSimpleResponse(t, response, actions, 20*time.Second, func(page *Page, err error, out ActionData) {
|
||||||
require.Nil(t, err, "could not run page actions")
|
require.Nil(t, err, "could not run page actions")
|
||||||
el := page.Page().MustElement("select")
|
el := page.Page().MustElement("select")
|
||||||
require.Equal(t, "Test2", el.MustText(), "could not get input change value")
|
require.Equal(t, "Test2", el.MustText(), "could not get input change value")
|
||||||
@ -311,7 +311,7 @@ func TestActionFilesInput(t *testing.T) {
|
|||||||
{ActionType: ActionTypeHolder{ActionType: ActionFilesInput}, Data: map[string]string{"selector": "input", "value": "test1.pdf"}},
|
{ActionType: ActionTypeHolder{ActionType: ActionFilesInput}, Data: map[string]string{"selector": "input", "value": "test1.pdf"}},
|
||||||
}
|
}
|
||||||
|
|
||||||
testHeadlessSimpleResponse(t, response, actions, 20*time.Second, func(page *Page, err error, out map[string]string) {
|
testHeadlessSimpleResponse(t, response, actions, 20*time.Second, func(page *Page, err error, out ActionData) {
|
||||||
require.Nil(t, err, "could not run page actions")
|
require.Nil(t, err, "could not run page actions")
|
||||||
require.Equal(t, "Nuclei Test Page", page.Page().MustInfo().Title, "could not navigate correctly")
|
require.Equal(t, "Nuclei Test Page", page.Page().MustInfo().Title, "could not navigate correctly")
|
||||||
el := page.Page().MustElement("input")
|
el := page.Page().MustElement("input")
|
||||||
@ -337,7 +337,7 @@ func TestActionFilesInputNegative(t *testing.T) {
|
|||||||
}
|
}
|
||||||
t.Setenv("LOCAL_FILE_ACCESS", "false")
|
t.Setenv("LOCAL_FILE_ACCESS", "false")
|
||||||
|
|
||||||
testHeadlessSimpleResponse(t, response, actions, 20*time.Second, func(page *Page, err error, out map[string]string) {
|
testHeadlessSimpleResponse(t, response, actions, 20*time.Second, func(page *Page, err error, out ActionData) {
|
||||||
require.ErrorContains(t, err, ErrLFAccessDenied.Error(), "got file access when -lfa is false")
|
require.ErrorContains(t, err, ErrLFAccessDenied.Error(), "got file access when -lfa is false")
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -359,7 +359,7 @@ func TestActionWaitLoad(t *testing.T) {
|
|||||||
{ActionType: ActionTypeHolder{ActionType: ActionWaitLoad}},
|
{ActionType: ActionTypeHolder{ActionType: ActionWaitLoad}},
|
||||||
}
|
}
|
||||||
|
|
||||||
testHeadlessSimpleResponse(t, response, actions, 20*time.Second, func(page *Page, err error, out map[string]string) {
|
testHeadlessSimpleResponse(t, response, actions, 20*time.Second, func(page *Page, err error, out ActionData) {
|
||||||
require.Nil(t, err, "could not run page actions")
|
require.Nil(t, err, "could not run page actions")
|
||||||
el := page.Page().MustElement("button")
|
el := page.Page().MustElement("button")
|
||||||
style, attributeErr := el.Attribute("style")
|
style, attributeErr := el.Attribute("style")
|
||||||
@ -384,9 +384,12 @@ func TestActionGetResource(t *testing.T) {
|
|||||||
{ActionType: ActionTypeHolder{ActionType: ActionGetResource}, Data: map[string]string{"by": "x", "xpath": "//img[@id='test']"}, Name: "src"},
|
{ActionType: ActionTypeHolder{ActionType: ActionGetResource}, Data: map[string]string{"by": "x", "xpath": "//img[@id='test']"}, Name: "src"},
|
||||||
}
|
}
|
||||||
|
|
||||||
testHeadlessSimpleResponse(t, response, actions, 20*time.Second, func(page *Page, err error, out map[string]string) {
|
testHeadlessSimpleResponse(t, response, actions, 20*time.Second, func(page *Page, err error, out ActionData) {
|
||||||
require.Nil(t, err, "could not run page actions")
|
require.Nil(t, err, "could not run page actions")
|
||||||
require.Equal(t, len(out["src"]), 121808, "could not find resource")
|
|
||||||
|
src, ok := out["src"].(string)
|
||||||
|
require.True(t, ok, "could not assert src to string")
|
||||||
|
require.Equal(t, len(src), 121808, "could not find resource")
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -404,7 +407,7 @@ func TestActionExtract(t *testing.T) {
|
|||||||
{ActionType: ActionTypeHolder{ActionType: ActionExtract}, Data: map[string]string{"by": "x", "xpath": "//button[@id='test']"}, Name: "extract"},
|
{ActionType: ActionTypeHolder{ActionType: ActionExtract}, Data: map[string]string{"by": "x", "xpath": "//button[@id='test']"}, Name: "extract"},
|
||||||
}
|
}
|
||||||
|
|
||||||
testHeadlessSimpleResponse(t, response, actions, 20*time.Second, func(page *Page, err error, out map[string]string) {
|
testHeadlessSimpleResponse(t, response, actions, 20*time.Second, func(page *Page, err error, out ActionData) {
|
||||||
require.Nil(t, err, "could not run page actions")
|
require.Nil(t, err, "could not run page actions")
|
||||||
require.Equal(t, "Wait for me!", out["extract"], "could not extract text")
|
require.Equal(t, "Wait for me!", out["extract"], "could not extract text")
|
||||||
})
|
})
|
||||||
@ -423,7 +426,7 @@ func TestActionSetMethod(t *testing.T) {
|
|||||||
{ActionType: ActionTypeHolder{ActionType: ActionSetMethod}, Data: map[string]string{"part": "x", "method": "SET"}},
|
{ActionType: ActionTypeHolder{ActionType: ActionSetMethod}, Data: map[string]string{"part": "x", "method": "SET"}},
|
||||||
}
|
}
|
||||||
|
|
||||||
testHeadlessSimpleResponse(t, response, actions, 20*time.Second, func(page *Page, err error, out map[string]string) {
|
testHeadlessSimpleResponse(t, response, actions, 20*time.Second, func(page *Page, err error, out ActionData) {
|
||||||
require.Nil(t, err, "could not run page actions")
|
require.Nil(t, err, "could not run page actions")
|
||||||
require.Equal(t, "SET", page.rules[0].Args["method"], "could not find resource")
|
require.Equal(t, "SET", page.rules[0].Args["method"], "could not find resource")
|
||||||
})
|
})
|
||||||
@ -442,7 +445,7 @@ func TestActionAddHeader(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
testHeadless(t, actions, 20*time.Second, handler, func(page *Page, err error, out map[string]string) {
|
testHeadless(t, actions, 20*time.Second, handler, func(page *Page, err error, out ActionData) {
|
||||||
require.Nil(t, err, "could not run page actions")
|
require.Nil(t, err, "could not run page actions")
|
||||||
require.Equal(t, "found", strings.ToLower(strings.TrimSpace(page.Page().MustElement("html").MustText())), "could not set header correctly")
|
require.Equal(t, "found", strings.ToLower(strings.TrimSpace(page.Page().MustElement("html").MustText())), "could not set header correctly")
|
||||||
})
|
})
|
||||||
@ -463,7 +466,7 @@ func TestActionDeleteHeader(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
testHeadless(t, actions, 20*time.Second, handler, func(page *Page, err error, out map[string]string) {
|
testHeadless(t, actions, 20*time.Second, handler, func(page *Page, err error, out ActionData) {
|
||||||
require.Nil(t, err, "could not run page actions")
|
require.Nil(t, err, "could not run page actions")
|
||||||
require.Equal(t, "header deleted", strings.ToLower(strings.TrimSpace(page.Page().MustElement("html").MustText())), "could not delete header correctly")
|
require.Equal(t, "header deleted", strings.ToLower(strings.TrimSpace(page.Page().MustElement("html").MustText())), "could not delete header correctly")
|
||||||
})
|
})
|
||||||
@ -481,7 +484,7 @@ func TestActionSetBody(t *testing.T) {
|
|||||||
_, _ = fmt.Fprintln(w, string(body))
|
_, _ = fmt.Fprintln(w, string(body))
|
||||||
}
|
}
|
||||||
|
|
||||||
testHeadless(t, actions, 20*time.Second, handler, func(page *Page, err error, out map[string]string) {
|
testHeadless(t, actions, 20*time.Second, handler, func(page *Page, err error, out ActionData) {
|
||||||
require.Nil(t, err, "could not run page actions")
|
require.Nil(t, err, "could not run page actions")
|
||||||
require.Equal(t, "hello", strings.ToLower(strings.TrimSpace(page.Page().MustElement("html").MustText())), "could not set header correctly")
|
require.Equal(t, "hello", strings.ToLower(strings.TrimSpace(page.Page().MustElement("html").MustText())), "could not set header correctly")
|
||||||
})
|
})
|
||||||
@ -505,7 +508,7 @@ func TestActionKeyboard(t *testing.T) {
|
|||||||
{ActionType: ActionTypeHolder{ActionType: ActionKeyboard}, Data: map[string]string{"keys": "Test2"}},
|
{ActionType: ActionTypeHolder{ActionType: ActionKeyboard}, Data: map[string]string{"keys": "Test2"}},
|
||||||
}
|
}
|
||||||
|
|
||||||
testHeadlessSimpleResponse(t, response, actions, 20*time.Second, func(page *Page, err error, out map[string]string) {
|
testHeadlessSimpleResponse(t, response, actions, 20*time.Second, func(page *Page, err error, out ActionData) {
|
||||||
require.Nil(t, err, "could not run page actions")
|
require.Nil(t, err, "could not run page actions")
|
||||||
el := page.Page().MustElement("input")
|
el := page.Page().MustElement("input")
|
||||||
require.Equal(t, "Test2", el.MustText(), "could not get input change value")
|
require.Equal(t, "Test2", el.MustText(), "could not get input change value")
|
||||||
@ -529,7 +532,7 @@ func TestActionSleep(t *testing.T) {
|
|||||||
{ActionType: ActionTypeHolder{ActionType: ActionSleep}, Data: map[string]string{"duration": "2"}},
|
{ActionType: ActionTypeHolder{ActionType: ActionSleep}, Data: map[string]string{"duration": "2"}},
|
||||||
}
|
}
|
||||||
|
|
||||||
testHeadlessSimpleResponse(t, response, actions, 20*time.Second, func(page *Page, err error, out map[string]string) {
|
testHeadlessSimpleResponse(t, response, actions, 20*time.Second, func(page *Page, err error, out ActionData) {
|
||||||
require.Nil(t, err, "could not run page actions")
|
require.Nil(t, err, "could not run page actions")
|
||||||
require.True(t, page.Page().MustElement("button").MustVisible(), "could not get button")
|
require.True(t, page.Page().MustElement("button").MustVisible(), "could not get button")
|
||||||
})
|
})
|
||||||
@ -553,7 +556,7 @@ func TestActionWaitVisible(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
t.Run("wait for an element being visible", func(t *testing.T) {
|
t.Run("wait for an element being visible", func(t *testing.T) {
|
||||||
testHeadlessSimpleResponse(t, response, actions, 2*time.Second, func(page *Page, err error, out map[string]string) {
|
testHeadlessSimpleResponse(t, response, actions, 2*time.Second, func(page *Page, err error, out ActionData) {
|
||||||
require.Nil(t, err, "could not run page actions")
|
require.Nil(t, err, "could not run page actions")
|
||||||
|
|
||||||
page.Page().MustElement("button").MustVisible()
|
page.Page().MustElement("button").MustVisible()
|
||||||
@ -562,21 +565,82 @@ func TestActionWaitVisible(t *testing.T) {
|
|||||||
|
|
||||||
t.Run("timeout because of element not visible", func(t *testing.T) {
|
t.Run("timeout because of element not visible", func(t *testing.T) {
|
||||||
// increased timeout from time.Second/2 to time.Second due to random fails (probably due to overhead and system)
|
// increased timeout from time.Second/2 to time.Second due to random fails (probably due to overhead and system)
|
||||||
testHeadlessSimpleResponse(t, response, actions, time.Second, func(page *Page, err error, out map[string]string) {
|
testHeadlessSimpleResponse(t, response, actions, time.Second, func(page *Page, err error, out ActionData) {
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
require.Contains(t, err.Error(), "Element did not appear in the given amount of time")
|
require.Contains(t, err.Error(), "Element did not appear in the given amount of time")
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func testHeadlessSimpleResponse(t *testing.T, response string, actions []*Action, timeout time.Duration, assert func(page *Page, pageErr error, out map[string]string)) {
|
func TestActionWaitDialog(t *testing.T) {
|
||||||
|
response := `<html>
|
||||||
|
<head>
|
||||||
|
<title>Nuclei Test Page</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<script type="text/javascript">
|
||||||
|
const urlParams = new URLSearchParams(window.location.search);
|
||||||
|
const scriptContent = urlParams.get('script');
|
||||||
|
if (scriptContent) {
|
||||||
|
const scriptElement = document.createElement('script');
|
||||||
|
scriptElement.textContent = scriptContent;
|
||||||
|
|
||||||
|
document.body.appendChild(scriptElement);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>`
|
||||||
|
|
||||||
|
t.Run("Triggered", func(t *testing.T) {
|
||||||
|
actions := []*Action{
|
||||||
|
{
|
||||||
|
ActionType: ActionTypeHolder{ActionType: ActionNavigate},
|
||||||
|
Data: map[string]string{"url": "{{BaseURL}}/?script=alert%281%29"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ActionType: ActionTypeHolder{ActionType: ActionWaitDialog},
|
||||||
|
Name: "test",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
testHeadlessSimpleResponse(t, response, actions, 1*time.Second, func(page *Page, err error, out ActionData) {
|
||||||
|
require.Nil(t, err, "could not run page actions")
|
||||||
|
|
||||||
|
test, ok := out["test"].(bool)
|
||||||
|
require.True(t, ok, "could not assert test to bool")
|
||||||
|
require.True(t, test, "could not find test")
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Invalid", func(t *testing.T) {
|
||||||
|
actions := []*Action{
|
||||||
|
{
|
||||||
|
ActionType: ActionTypeHolder{ActionType: ActionNavigate},
|
||||||
|
Data: map[string]string{"url": "{{BaseURL}}/?script=foo"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ActionType: ActionTypeHolder{ActionType: ActionWaitDialog},
|
||||||
|
Name: "test",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
testHeadlessSimpleResponse(t, response, actions, 1*time.Second, func(page *Page, err error, out ActionData) {
|
||||||
|
require.Nil(t, err, "could not run page actions")
|
||||||
|
|
||||||
|
_, ok := out["test"].(bool)
|
||||||
|
require.False(t, ok, "output assertion is success")
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func testHeadlessSimpleResponse(t *testing.T, response string, actions []*Action, timeout time.Duration, assert func(page *Page, pageErr error, out ActionData)) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
testHeadless(t, actions, timeout, func(w http.ResponseWriter, r *http.Request) {
|
testHeadless(t, actions, timeout, func(w http.ResponseWriter, r *http.Request) {
|
||||||
_, _ = fmt.Fprintln(w, response)
|
_, _ = fmt.Fprintln(w, response)
|
||||||
}, assert)
|
}, assert)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testHeadless(t *testing.T, actions []*Action, timeout time.Duration, handler func(w http.ResponseWriter, r *http.Request), assert func(page *Page, pageErr error, extractedData map[string]string)) {
|
func testHeadless(t *testing.T, actions []*Action, timeout time.Duration, handler func(w http.ResponseWriter, r *http.Request), assert func(page *Page, pageErr error, extractedData ActionData)) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
lfa := getBoolFromEnv("LOCAL_FILE_ACCESS", true)
|
lfa := getBoolFromEnv("LOCAL_FILE_ACCESS", true)
|
||||||
|
|||||||
@ -183,7 +183,13 @@ func (request *Request) executeRequestWithPayloads(input *contextargs.Context, p
|
|||||||
responseBody, _ = html.HTML()
|
responseBody, _ = html.HTML()
|
||||||
}
|
}
|
||||||
|
|
||||||
outputEvent := request.responseToDSLMap(responseBody, out["header"], out["status_code"], reqBuilder.String(), input.MetaInput.Input, navigatedURL, page.DumpHistory())
|
header := out.GetOrDefault("header", "").(string)
|
||||||
|
|
||||||
|
// NOTE(dwisiswant0): `status_code` key should be an integer type.
|
||||||
|
// Ref: https://github.com/projectdiscovery/nuclei/pull/5545#discussion_r1721291013
|
||||||
|
statusCode := out.GetOrDefault("status_code", "").(string)
|
||||||
|
|
||||||
|
outputEvent := request.responseToDSLMap(responseBody, header, statusCode, reqBuilder.String(), input.MetaInput.Input, navigatedURL, page.DumpHistory())
|
||||||
// add response fields to template context and merge templatectx variables to output event
|
// add response fields to template context and merge templatectx variables to output event
|
||||||
request.options.AddTemplateVars(input.MetaInput, request.Type(), request.ID, outputEvent)
|
request.options.AddTemplateVars(input.MetaInput, request.Type(), request.ID, outputEvent)
|
||||||
if request.options.HasTemplateCtx(input.MetaInput) {
|
if request.options.HasTemplateCtx(input.MetaInput) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user