Skip to content

Commit

Permalink
add headless options flag
Browse files Browse the repository at this point in the history
  • Loading branch information
dogancanbakir committed Jul 19, 2023
1 parent 0828339 commit b301b1b
Show file tree
Hide file tree
Showing 6 changed files with 95 additions and 5 deletions.
11 changes: 6 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -246,11 +246,12 @@ OPTIMIZATIONS:
-no-stdin disable stdin processing

HEADLESS:
-headless enable templates that require headless browser support (root user on Linux will disable sandbox)
-page-timeout int seconds to wait for each page in headless mode (default 20)
-sb, -show-browser show the browser on the screen when running templates with headless mode
-sc, -system-chrome use local installed Chrome browser instead of nuclei installed
-lha, -list-headless-action list available headless actions
-headless enable templates that require headless browser support (root user on Linux will disable sandbox)
-page-timeout int seconds to wait for each page in headless mode (default 20)
-sb, -show-browser show the browser on the screen when running templates with headless mode
-ho, -headless-options string[] start headless chrome with additional options
-sc, -system-chrome use local installed Chrome browser instead of nuclei installed
-lha, -list-headless-action list available headless actions

DEBUG:
-debug show all requests and responses
Expand Down
1 change: 1 addition & 0 deletions v2/cmd/nuclei/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,7 @@ on extensive configurability, massive extensibility and ease of use.`)
flagSet.BoolVar(&options.Headless, "headless", false, "enable templates that require headless browser support (root user on Linux will disable sandbox)"),
flagSet.IntVar(&options.PageTimeout, "page-timeout", 20, "seconds to wait for each page in headless mode"),
flagSet.BoolVarP(&options.ShowBrowser, "show-browser", "sb", false, "show the browser on the screen when running templates with headless mode"),
flagSet.StringSliceVarP(&options.HeadlessOptionalArguments, "headless-options", "ho", nil, "start headless chrome with additional options", goflags.FileCommaSeparatedStringSliceOptions),
flagSet.BoolVarP(&options.UseInstalledChrome, "system-chrome", "sc", false, "use local installed Chrome browser instead of nuclei installed"),
flagSet.BoolVarP(&options.ShowActions, "list-headless-action", "lha", false, "list available headless actions"),
)
Expand Down
4 changes: 4 additions & 0 deletions v2/internal/runner/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,10 @@ func validateOptions(options *types.Options) error {
return errors.New("both verbose and silent mode specified")
}

if (options.HeadlessOptionalArguments != nil || options.ShowBrowser || options.UseInstalledChrome) && !options.Headless {
return errors.New("headless mode (-headless) is required if -ho, -sb, -sc or -lha are set")
}

if options.FollowHostRedirects && options.FollowRedirects {
return errors.New("both follow host redirects and follow redirects specified")
}
Expand Down
61 changes: 61 additions & 0 deletions v2/internal/runner/options_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package runner

import (
"strings"
"testing"

"github.com/projectdiscovery/goflags"
"github.com/projectdiscovery/nuclei/v2/pkg/types"
"github.com/stretchr/testify/require"
)

func TestParseHeadlessOptionalArguments(t *testing.T) {
tests := []struct {
name string
input string
want map[string]string
}{
{
name: "single value",
input: "a=b",
want: map[string]string{"a": "b"},
},
{
name: "empty string",
input: "",
want: map[string]string{},
},
{
name: "empty key",
input: "=b",
want: map[string]string{},
},
{
name: "empty value",
input: "a=",
want: map[string]string{},
},
{
name: "double input",
input: "a=b,c=d",
want: map[string]string{"a": "b", "c": "d"},
},
{
name: "duplicated input",
input: "a=b,a=b",
want: map[string]string{"a": "b"},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
strsl := goflags.StringSlice{}
for _, v := range strings.Split(tt.input, ",") {
//nolint
strsl.Set(v)
}
opt := types.Options{HeadlessOptionalArguments: strsl}
got := opt.ParseHeadlessOptionalArguments()
require.Equal(t, tt.want, got)
})
}
}
6 changes: 6 additions & 0 deletions v2/pkg/protocols/headless/engine/engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (

"github.com/go-rod/rod"
"github.com/go-rod/rod/lib/launcher"
"github.com/go-rod/rod/lib/launcher/flags"
"github.com/pkg/errors"

"github.com/projectdiscovery/nuclei/v2/pkg/types"
Expand Down Expand Up @@ -75,6 +76,11 @@ func New(options *types.Options) (*Browser, error) {
if types.ProxyURL != "" {
chromeLauncher = chromeLauncher.Proxy(types.ProxyURL)
}

for k, v := range options.ParseHeadlessOptionalArguments() {
chromeLauncher.Set(flags.Flag(k), v)
}

launcherURL, err := chromeLauncher.Launch()
if err != nil {
return nil, err
Expand Down
17 changes: 17 additions & 0 deletions v2/pkg/types/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package types

import (
"io"
"strings"
"time"

"github.com/projectdiscovery/goflags"
Expand Down Expand Up @@ -195,6 +196,8 @@ type Options struct {
Headless bool
// ShowBrowser specifies whether the show the browser in headless mode
ShowBrowser bool
// HeadlessOptionalArguments specifies optional arguments to pass to Chrome
HeadlessOptionalArguments goflags.StringSlice
// NoTables disables pretty printing of cloud results in tables
NoTables bool
// DisableClustering disables clustering of templates
Expand Down Expand Up @@ -439,3 +442,17 @@ func (options *Options) HasCloudOptions() bool {
func (options *Options) ShouldUseHostError() bool {
return options.MaxHostError > 0 && !options.NoHostErrors
}

func (options *Options) ParseHeadlessOptionalArguments() map[string]string {
optionalArguments := make(map[string]string)
for _, v := range options.HeadlessOptionalArguments {
if argParts := strings.SplitN(v, "=", 2); len(argParts) >= 2 {
key := strings.TrimSpace(argParts[0])
value := strings.TrimSpace(argParts[1])
if key != "" && value != "" {
optionalArguments[key] = value
}
}
}
return optionalArguments
}

0 comments on commit b301b1b

Please sign in to comment.