mirror of
https://github.com/projectdiscovery/nuclei.git
synced 2026-11-07 17:43:04 -10:00
Compare commits
61
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
96203d8755 | ||
|
|
042b33de3d | ||
|
|
5bb730849c | ||
|
|
7bc257d7a5 | ||
|
|
04a6159713 | ||
|
|
0c4c0af4e9 | ||
|
|
cb05f55251 | ||
|
|
841d8913e5 | ||
|
|
9a5272985c | ||
|
|
fdb8e0a8c6 | ||
|
|
88b281ae47 | ||
|
|
e0b2542868 | ||
|
|
6b71af448a | ||
|
|
bf58b4d756 | ||
|
|
aac1af1308 | ||
|
|
4a85e73fbb | ||
|
|
c23e1864d6 | ||
|
|
2670b6865f | ||
|
|
b424ba9f50 | ||
|
|
faed7798fc | ||
|
|
253fbc3619 | ||
|
|
4a39fdb8d6 | ||
|
|
5627da8c19 | ||
|
|
710f1ad240 | ||
|
|
8c0dd5fac1 | ||
|
|
bac917428b | ||
|
|
5018673c0c | ||
|
|
71628cc897 | ||
|
|
7f51de3090 | ||
|
|
491233667d | ||
|
|
7f556f8e33 | ||
|
|
bce3e7f518 | ||
|
|
5957381c02 | ||
|
|
3f82fc6d00 | ||
|
|
4d12271ccf | ||
|
|
39b6ca9bb7 | ||
|
|
9957003113 | ||
|
|
930f51fcf0 | ||
|
|
af2284b741 | ||
|
|
cda1fc0ba5 | ||
|
|
0f4ad124e4 | ||
|
|
7d031d9833 | ||
|
|
669eee24bd | ||
|
|
1f38d6b459 | ||
|
|
b38bcdfd81 | ||
|
|
7f2558fc12 | ||
|
|
5eac841424 | ||
|
|
c3b39be605 | ||
|
|
6072a2fcee | ||
|
|
2a7e15ddfa | ||
|
|
3a7a073d52 | ||
|
|
918b62bd35 | ||
|
|
106ab84259 | ||
|
|
85d888b01a | ||
|
|
9f18a99db7 | ||
|
|
9606591dc9 | ||
|
|
19567fb77b | ||
|
|
2d14849674 | ||
|
|
cc46f57d4d | ||
|
|
75357b1eea | ||
|
|
5aa929ac7f |
No files matched your search
@@ -3,6 +3,5 @@ reviewers:
|
||||
- dogancanbakir
|
||||
|
||||
numberOfReviewers: 1
|
||||
# A list of keywords to be skipped the process that add reviewers if pull requests include it
|
||||
# skipKeywords:
|
||||
# - wip
|
||||
skipKeywords:
|
||||
- '@dependabot'
|
||||
+1
-1
@@ -9,7 +9,7 @@ RUN go build ./cmd/nuclei
|
||||
|
||||
# Release
|
||||
FROM alpine:3.18.6
|
||||
RUN apk -U upgrade --no-cache \
|
||||
RUN apk upgrade --no-cache \
|
||||
&& apk add --no-cache bind-tools chromium ca-certificates
|
||||
COPY --from=build-env /app/nuclei /usr/local/bin/
|
||||
|
||||
|
||||
@@ -65,6 +65,7 @@ docs:
|
||||
|
||||
git reset --hard # line 59
|
||||
|
||||
test: GOFLAGS = -race -v
|
||||
test:
|
||||
$(GOTEST) $(GOFLAGS) ./...
|
||||
|
||||
|
||||
@@ -3682,6 +3682,8 @@ Enum Values:
|
||||
|
||||
- <code>waitevent</code>
|
||||
|
||||
- <code>dialog</code>
|
||||
|
||||
- <code>keyboard</code>
|
||||
|
||||
- <code>debug</code>
|
||||
|
||||
@@ -55,6 +55,7 @@ var (
|
||||
"dsl": dslTestcases,
|
||||
"flow": flowTestcases,
|
||||
"javascript": jsTestcases,
|
||||
"matcher-status": matcherStatusTestcases,
|
||||
}
|
||||
// flakyTests are run with a retry count of 3
|
||||
flakyTests = map[string]bool{
|
||||
|
||||
@@ -0,0 +1,119 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/output"
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/testutils"
|
||||
)
|
||||
|
||||
var matcherStatusTestcases = []TestCaseInfo{
|
||||
{Path: "protocols/http/get.yaml", TestCase: &httpNoAccess{}},
|
||||
{Path: "protocols/network/net-https.yaml", TestCase: &networkNoAccess{}},
|
||||
{Path: "protocols/headless/headless-basic.yaml", TestCase: &headlessNoAccess{}},
|
||||
{Path: "protocols/javascript/net-https.yaml", TestCase: &javascriptNoAccess{}},
|
||||
{Path: "protocols/websocket/basic.yaml", TestCase: &websocketNoAccess{}},
|
||||
{Path: "protocols/dns/a.yaml", TestCase: &dnsNoAccess{}},
|
||||
}
|
||||
|
||||
type httpNoAccess struct{}
|
||||
|
||||
func (h *httpNoAccess) Execute(filePath string) error {
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, "trust_me_bro.real", debug, "-ms", "-j")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
event := &output.ResultEvent{}
|
||||
_ = json.Unmarshal([]byte(results[0]), event)
|
||||
|
||||
if event.Error != "no address found for host" {
|
||||
return fmt.Errorf("unexpected result: expecting \"no address found for host\" error but got none")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type networkNoAccess struct{}
|
||||
|
||||
// Execute executes a test case and returns an error if occurred
|
||||
func (h *networkNoAccess) Execute(filePath string) error {
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, "trust_me_bro.real", debug, "-ms", "-j")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
event := &output.ResultEvent{}
|
||||
_ = json.Unmarshal([]byte(results[0]), event)
|
||||
|
||||
if event.Error != "no address found for host" {
|
||||
return fmt.Errorf("unexpected result: expecting \"no address found for host\" error but got \"%s\"", event.Error)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type headlessNoAccess struct{}
|
||||
|
||||
// Execute executes a test case and returns an error if occurred
|
||||
func (h *headlessNoAccess) Execute(filePath string) error {
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, "trust_me_bro.real", debug, "-headless", "-ms", "-j")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
event := &output.ResultEvent{}
|
||||
_ = json.Unmarshal([]byte(results[0]), event)
|
||||
|
||||
if event.Error == "" {
|
||||
return fmt.Errorf("unexpected result: expecting an error but got \"%s\"", event.Error)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type javascriptNoAccess struct{}
|
||||
|
||||
// Execute executes a test case and returns an error if occurred
|
||||
func (h *javascriptNoAccess) Execute(filePath string) error {
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, "trust_me_bro.real", debug, "-ms", "-j")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
event := &output.ResultEvent{}
|
||||
_ = json.Unmarshal([]byte(results[0]), event)
|
||||
|
||||
if event.Error == "" {
|
||||
return fmt.Errorf("unexpected result: expecting an error but got \"%s\"", event.Error)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type websocketNoAccess struct{}
|
||||
|
||||
// Execute executes a test case and returns an error if occurred
|
||||
func (h *websocketNoAccess) Execute(filePath string) error {
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, "ws://trust_me_bro.real", debug, "-ms", "-j")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
event := &output.ResultEvent{}
|
||||
_ = json.Unmarshal([]byte(results[0]), event)
|
||||
|
||||
if event.Error == "" {
|
||||
return fmt.Errorf("unexpected result: expecting an error but got \"%s\"", event.Error)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type dnsNoAccess struct{}
|
||||
|
||||
// Execute executes a test case and returns an error if occurred
|
||||
func (h *dnsNoAccess) Execute(filePath string) error {
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, "trust_me_bro.real", debug, "-ms", "-j")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
event := &output.ResultEvent{}
|
||||
_ = json.Unmarshal([]byte(results[0]), event)
|
||||
|
||||
if event.Error == "" {
|
||||
return fmt.Errorf("unexpected result: expecting an error but got \"%s\"", event.Error)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
+1
-1
@@ -300,7 +300,7 @@ func formatTemplate(data string) (string, bool, error) {
|
||||
return data, false, errorutil.New("template format failed")
|
||||
}
|
||||
|
||||
// lintTemplateData lints template data using templateman lint api
|
||||
// lintTemplate lints template data using templateman lint api
|
||||
func lintTemplate(data string) (bool, error) {
|
||||
resp, err := retryablehttp.DefaultClient().Post(fmt.Sprintf("%s/lint", tmBaseUrl), "application/x-yaml", strings.NewReader(data))
|
||||
if err != nil {
|
||||
|
||||
@@ -20,12 +20,12 @@ require (
|
||||
github.com/olekukonko/tablewriter v0.0.5
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/projectdiscovery/clistats v0.1.0
|
||||
github.com/projectdiscovery/fastdialer v0.2.5
|
||||
github.com/projectdiscovery/hmap v0.0.55
|
||||
github.com/projectdiscovery/fastdialer v0.2.7
|
||||
github.com/projectdiscovery/hmap v0.0.56
|
||||
github.com/projectdiscovery/interactsh v1.2.0
|
||||
github.com/projectdiscovery/rawhttp v0.1.60
|
||||
github.com/projectdiscovery/retryabledns v1.0.72
|
||||
github.com/projectdiscovery/retryablehttp-go v1.0.74
|
||||
github.com/projectdiscovery/rawhttp v0.1.61
|
||||
github.com/projectdiscovery/retryabledns v1.0.73
|
||||
github.com/projectdiscovery/retryablehttp-go v1.0.76
|
||||
github.com/projectdiscovery/yamldoc-go v1.0.4
|
||||
github.com/remeh/sizedwaitgroup v1.0.0
|
||||
github.com/rs/xid v1.5.0
|
||||
@@ -72,6 +72,7 @@ require (
|
||||
github.com/go-sql-driver/mysql v1.7.1
|
||||
github.com/h2non/filetype v1.1.3
|
||||
github.com/invopop/yaml v0.3.1
|
||||
github.com/kitabisa/go-ci v1.0.2
|
||||
github.com/labstack/echo/v4 v4.10.2
|
||||
github.com/leslie-qiwa/flat v0.0.0-20230424180412-f9d1cf014baa
|
||||
github.com/lib/pq v1.10.9
|
||||
@@ -80,23 +81,23 @@ require (
|
||||
github.com/microsoft/go-mssqldb v1.6.0
|
||||
github.com/ory/dockertest/v3 v3.10.0
|
||||
github.com/praetorian-inc/fingerprintx v1.1.9
|
||||
github.com/projectdiscovery/dsl v0.1.8
|
||||
github.com/projectdiscovery/dsl v0.2.1
|
||||
github.com/projectdiscovery/fasttemplate v0.0.2
|
||||
github.com/projectdiscovery/go-smb2 v0.0.0-20240129202741-052cc450c6cb
|
||||
github.com/projectdiscovery/goflags v0.1.63
|
||||
github.com/projectdiscovery/gologger v1.1.19
|
||||
github.com/projectdiscovery/goflags v0.1.64
|
||||
github.com/projectdiscovery/gologger v1.1.21
|
||||
github.com/projectdiscovery/gostruct v0.0.2
|
||||
github.com/projectdiscovery/gozero v0.0.2
|
||||
github.com/projectdiscovery/httpx v1.6.7
|
||||
github.com/projectdiscovery/httpx v1.6.8
|
||||
github.com/projectdiscovery/mapcidr v1.1.34
|
||||
github.com/projectdiscovery/n3iwf v0.0.0-20230523120440-b8cd232ff1f5
|
||||
github.com/projectdiscovery/ratelimit v0.0.49
|
||||
github.com/projectdiscovery/ratelimit v0.0.53
|
||||
github.com/projectdiscovery/rdap v0.9.1-0.20221108103045-9865884d1917
|
||||
github.com/projectdiscovery/sarif v0.0.1
|
||||
github.com/projectdiscovery/tlsx v1.1.6
|
||||
github.com/projectdiscovery/tlsx v1.1.7
|
||||
github.com/projectdiscovery/uncover v1.0.9
|
||||
github.com/projectdiscovery/useragent v0.0.65
|
||||
github.com/projectdiscovery/utils v0.2.5
|
||||
github.com/projectdiscovery/utils v0.2.7
|
||||
github.com/projectdiscovery/wappalyzergo v0.1.14
|
||||
github.com/redis/go-redis/v9 v9.1.0
|
||||
github.com/seh-msft/burpxml v1.0.1
|
||||
|
||||
@@ -625,6 +625,8 @@ github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF
|
||||
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/kitabisa/go-ci v1.0.2 h1:rqHf8KEbQOxVb998TbqGRo70Z7ol44io7/jLYJUvKp8=
|
||||
github.com/kitabisa/go-ci v1.0.2/go.mod h1:e3wBSzaJbcifXrr/Gw2ZBLn44MmeqP5WySwXyHlCK/U=
|
||||
github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
|
||||
github.com/klauspost/compress v1.11.4/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
|
||||
github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU=
|
||||
@@ -830,28 +832,28 @@ github.com/projectdiscovery/cdncheck v1.1.0 h1:qDITidmJsejzpk3rMkauCh6sjI2GH9hW/
|
||||
github.com/projectdiscovery/cdncheck v1.1.0/go.mod h1:sZ8U4MjHSsyaTVjBbYWHT1cwUVvUYwDX1W+WvWRicIc=
|
||||
github.com/projectdiscovery/clistats v0.1.0 h1:b+LF1w0xhNd7cneKWMXb+/yUmF1n5szawxP4XGpmbxs=
|
||||
github.com/projectdiscovery/clistats v0.1.0/go.mod h1:GJ2av0KnOvK0AISQnP8hyDclYIji1LVkx2l0pwnzAu4=
|
||||
github.com/projectdiscovery/dsl v0.1.8 h1:ulz+o097XsYgqP4QXaAQhVSkoeD2ZPWd29wX3CTodUA=
|
||||
github.com/projectdiscovery/dsl v0.1.8/go.mod h1:AYJS2WQ/q0smr2v4pEJTg4DPe6k56KFKR7UFXvzNz/4=
|
||||
github.com/projectdiscovery/fastdialer v0.2.5 h1:OZg31LFIBBHbXVnOEcFNtD0gBM80zpY68QvYI0xbw80=
|
||||
github.com/projectdiscovery/fastdialer v0.2.5/go.mod h1:E1vmos7AeD/KZ7rsDeImjLp5H3jjas+2utVdUxGulvY=
|
||||
github.com/projectdiscovery/dsl v0.2.1 h1:TK3KD4jsg4YbvY7WJqnz1QyH4AOvAwezeBFOX97Evgk=
|
||||
github.com/projectdiscovery/dsl v0.2.1/go.mod h1:IRQXsmi5/g1dDZ79//A9t2vrRtxm4frRSd5t8CZVSbI=
|
||||
github.com/projectdiscovery/fastdialer v0.2.7 h1:x7bEf/kDyVOuG9kHfJLMhWO3h7J+6fMDgLWkGYL8EFg=
|
||||
github.com/projectdiscovery/fastdialer v0.2.7/go.mod h1:7/BGdaw7sCekuBh6lLZqPuoO5N0Qaizwvex/PjO+V8o=
|
||||
github.com/projectdiscovery/fasttemplate v0.0.2 h1:h2cISk5xDhlJEinlBQS6RRx0vOlOirB2y3Yu4PJzpiA=
|
||||
github.com/projectdiscovery/fasttemplate v0.0.2/go.mod h1:XYWWVMxnItd+r0GbjA1GCsUopMw1/XusuQxdyAIHMCw=
|
||||
github.com/projectdiscovery/freeport v0.0.5 h1:jnd3Oqsl4S8n0KuFkE5Hm8WGDP24ITBvmyw5pFTHS8Q=
|
||||
github.com/projectdiscovery/freeport v0.0.5/go.mod h1:PY0bxSJ34HVy67LHIeF3uIutiCSDwOqKD8ruBkdiCwE=
|
||||
github.com/projectdiscovery/go-smb2 v0.0.0-20240129202741-052cc450c6cb h1:rutG906Drtbpz4DwU5mhGIeOhRcktDH4cGQitGUMAsg=
|
||||
github.com/projectdiscovery/go-smb2 v0.0.0-20240129202741-052cc450c6cb/go.mod h1:FLjF1DmZ+POoGEiIQdWuYVwS++C/GwpX8YaCsTSm1RY=
|
||||
github.com/projectdiscovery/goflags v0.1.63 h1:xy3nqpzmSFEmG0LKTv3xLcp9LMbvbFkLZcjcnFe3xR4=
|
||||
github.com/projectdiscovery/goflags v0.1.63/go.mod h1:ptFbCm+5RmSHTSG4oniwBRRHJlguBTOOfMUfezeGbZ0=
|
||||
github.com/projectdiscovery/gologger v1.1.19 h1:b7cU32XuDrDiwhr7hlDeE6mfj/nENBtHEohe51txJCE=
|
||||
github.com/projectdiscovery/gologger v1.1.19/go.mod h1:DbeKwx9IEfcvnclImX5gBlhIKUuOZwOM5itdpYXl+54=
|
||||
github.com/projectdiscovery/goflags v0.1.64 h1:FDfwdt9N97Hi8OuhbkDlKtVttpc/CRMIWQVa08VsHsI=
|
||||
github.com/projectdiscovery/goflags v0.1.64/go.mod h1:3FyHIVQtnycNOc1LE3O1jj/XR5XuMdF9QfHd0ujhnX4=
|
||||
github.com/projectdiscovery/gologger v1.1.21 h1:FD9MGE9adY/y2IxDpQgPZIvZAkQIx3bvcuY+d1FLQUo=
|
||||
github.com/projectdiscovery/gologger v1.1.21/go.mod h1:eyvlcHiSuzJQtwmh+fcfwZVaqVgSGtEP1oL1gJFgP3c=
|
||||
github.com/projectdiscovery/gostruct v0.0.2 h1:s8gP8ApugGM4go1pA+sVlPDXaWqNP5BBDDSv7VEdG1M=
|
||||
github.com/projectdiscovery/gostruct v0.0.2/go.mod h1:H86peL4HKwMXcQQtEa6lmC8FuD9XFt6gkNR0B/Mu5PE=
|
||||
github.com/projectdiscovery/gozero v0.0.2 h1:8fJeaCjxL9tpm33uG/RsCQs6HGM/NE6eA3cjkilRQ+E=
|
||||
github.com/projectdiscovery/gozero v0.0.2/go.mod h1:d8bZvDWW07LWNYWrwjZ4OO1I0cpkfqaysyDfSs9ibK8=
|
||||
github.com/projectdiscovery/hmap v0.0.55 h1:By0qSeQRE/ybeITUEL6oURN+j7qX7FVjCq92duwsqcA=
|
||||
github.com/projectdiscovery/hmap v0.0.55/go.mod h1:uZOF/W8yOGDb/t9omqATirhVwiboa5F/c00OVhDeE0E=
|
||||
github.com/projectdiscovery/httpx v1.6.7 h1:luJAtQ+iKpiyKKDpcWw1/fF1MaRX6JZ4R3P+ol5Uikk=
|
||||
github.com/projectdiscovery/httpx v1.6.7/go.mod h1:rqcuexBrb4v36ZyX0BHcHaovTurOJn2P65Tdt9cYdfE=
|
||||
github.com/projectdiscovery/hmap v0.0.56 h1:QLIuFhCc7jrBH9WYpxNBDooSoH+/S8cCm7VO5rMt3lU=
|
||||
github.com/projectdiscovery/hmap v0.0.56/go.mod h1:XyGKMO93nLOzpaTTCDBSKEGx/XWXjSpoyZJxT92Qd/Q=
|
||||
github.com/projectdiscovery/httpx v1.6.8 h1:k0Y5g3ue/7QbDP0+LykIxp/VhPDLfau3UEUyuxtP7qE=
|
||||
github.com/projectdiscovery/httpx v1.6.8/go.mod h1:7BIsDxyRwkBjthqFmEajXrA5f3yb4tlVfLmpNdf0ZXA=
|
||||
github.com/projectdiscovery/interactsh v1.2.0 h1:Al6jHiR+Usl9egYJDLJaWNHOcH8Rugk8gWMasc8Cmw8=
|
||||
github.com/projectdiscovery/interactsh v1.2.0/go.mod h1:Wxt0fnzxsfrAZQQlpVrf3xMatP4OXZaZbjuDkIQKdYY=
|
||||
github.com/projectdiscovery/ldapserver v1.0.2-0.20240219154113-dcc758ebc0cb h1:MGtI4oE12ruWv11ZlPXXd7hl/uAaQZrFvrIDYDeVMd8=
|
||||
@@ -864,28 +866,28 @@ github.com/projectdiscovery/n3iwf v0.0.0-20230523120440-b8cd232ff1f5 h1:L/e8z8yw
|
||||
github.com/projectdiscovery/n3iwf v0.0.0-20230523120440-b8cd232ff1f5/go.mod h1:pGW2ncnTxTxHtP9wzcIJAB+3/NMp6IiuQWd2NK7K+oc=
|
||||
github.com/projectdiscovery/networkpolicy v0.0.9 h1:IrlDoYZagNNO8y+7iZeHT8k5izE+nek7TdtvEBwCxqk=
|
||||
github.com/projectdiscovery/networkpolicy v0.0.9/go.mod h1:XFJ2Lnv8BE/ziQCFjBHMsH1w6VmkPiQtk+NlBpdMU7M=
|
||||
github.com/projectdiscovery/ratelimit v0.0.49 h1:PYatMp8g5OuoFsZOA90e48nLd2vB6a4Tw0FZ8h9zqkQ=
|
||||
github.com/projectdiscovery/ratelimit v0.0.49/go.mod h1:Xi0LTMHg4HQlmCZFzRBIhRW6N+QW5RxQ8V/Qs+Vta4k=
|
||||
github.com/projectdiscovery/rawhttp v0.1.60 h1:L57kAATGRuCfOp8Fs0ly3j2wlip7R5pco2RVfwqh/II=
|
||||
github.com/projectdiscovery/rawhttp v0.1.60/go.mod h1:M97w6lsphTHKeqLSio4Lw9K4KLO2riJMYAOqVMIZ3ck=
|
||||
github.com/projectdiscovery/ratelimit v0.0.53 h1:1ci2zaVCtJ9daDi9IXjNwpDxl2InYq375role/xqUR4=
|
||||
github.com/projectdiscovery/ratelimit v0.0.53/go.mod h1:4kNYTL7xKLo1qMYHTREUCBqHyvykFF+XBWutTh9fkwg=
|
||||
github.com/projectdiscovery/rawhttp v0.1.61 h1:EbskCj6kkDSG31sO5zEUFTqHp9ltccG1DdcI+MCdahQ=
|
||||
github.com/projectdiscovery/rawhttp v0.1.61/go.mod h1:5XmDAKph9pLVnh87zjL+vXDpfG5W8Gz5N2BAtYTkuVU=
|
||||
github.com/projectdiscovery/rdap v0.9.1-0.20221108103045-9865884d1917 h1:m03X4gBVSorSzvmm0bFa7gDV4QNSOWPL/fgZ4kTXBxk=
|
||||
github.com/projectdiscovery/rdap v0.9.1-0.20221108103045-9865884d1917/go.mod h1:JxXtZC9e195awe7EynrcnBJmFoad/BNDzW9mzFkK8Sg=
|
||||
github.com/projectdiscovery/retryabledns v1.0.72 h1:+k9JRYBMpZIyEQZJWVHoCHx1TEdpiuAS7iEru2bhs3A=
|
||||
github.com/projectdiscovery/retryabledns v1.0.72/go.mod h1:BDhYnqSH0Os2G37eb4L4vnKrUcik6Q6pR02Cq5PbT+0=
|
||||
github.com/projectdiscovery/retryablehttp-go v1.0.74 h1:jXZsg3nNDuDjGNeL0+hiEx/dqUqPyZW1zsotWW1y70c=
|
||||
github.com/projectdiscovery/retryablehttp-go v1.0.74/go.mod h1:fVRxa2fVMbomaPiOFA05kM2WrjV8wPFHW7J84eenVmQ=
|
||||
github.com/projectdiscovery/retryabledns v1.0.73 h1:CLqtgoI6+YVcUE2jnZPFVvwj59CHDE4HNImLf62sSuw=
|
||||
github.com/projectdiscovery/retryabledns v1.0.73/go.mod h1:Wo5tQHKtx6XcYYhMypRg8dr0GGnqIb4CzoTSEw2lo7I=
|
||||
github.com/projectdiscovery/retryablehttp-go v1.0.76 h1:2+4QpWnXUZFBkoeCEBXtUjSeBTdgKtaGwP8LRtKAC3g=
|
||||
github.com/projectdiscovery/retryablehttp-go v1.0.76/go.mod h1:0qIv7Ld8WWSKWYXMsNAWRYU5gsxnxpBza3SjDgt6nVc=
|
||||
github.com/projectdiscovery/sarif v0.0.1 h1:C2Tyj0SGOKbCLgHrx83vaE6YkzXEVrMXYRGLkKCr/us=
|
||||
github.com/projectdiscovery/sarif v0.0.1/go.mod h1:cEYlDu8amcPf6b9dSakcz2nNnJsoz4aR6peERwV+wuQ=
|
||||
github.com/projectdiscovery/stringsutil v0.0.2 h1:uzmw3IVLJSMW1kEg8eCStG/cGbYYZAja8BH3LqqJXMA=
|
||||
github.com/projectdiscovery/stringsutil v0.0.2/go.mod h1:EJ3w6bC5fBYjVou6ryzodQq37D5c6qbAYQpGmAy+DC0=
|
||||
github.com/projectdiscovery/tlsx v1.1.6 h1:iw2zwKbd2+kRQ8J1G4dLmS0CLyemd/tKz1UzcNsC77A=
|
||||
github.com/projectdiscovery/tlsx v1.1.6/go.mod h1:s7SRRFdrwIZBK/RXXZi4CR/CubqFSvp8h5Bk1srEZIo=
|
||||
github.com/projectdiscovery/tlsx v1.1.7 h1:eSsl/SmTDL/z2CMeSrbssk4f/9oOotMP1SgXl3yynSM=
|
||||
github.com/projectdiscovery/tlsx v1.1.7/go.mod h1:g66QQ4/y4tLVjoGbzWIv+Q6xwFzxfJbEDx86Y1dYHDM=
|
||||
github.com/projectdiscovery/uncover v1.0.9 h1:s5RbkD/V4r8QcPkys4gTTqMuRSgXq0JprejqLSopN9Y=
|
||||
github.com/projectdiscovery/uncover v1.0.9/go.mod h1:2PUF3SpB5QNIJ8epaB2xbRzkPaxEAWRDm3Ir2ijt81U=
|
||||
github.com/projectdiscovery/useragent v0.0.65 h1:x78ZwWdqpzokOHxLITUXvq+ljkTKc19z3ILGtoV1N70=
|
||||
github.com/projectdiscovery/useragent v0.0.65/go.mod h1:deOP8YLJU6SCzM8k+K8PjkcOF4Ux0spqyO4ODZGIT4A=
|
||||
github.com/projectdiscovery/utils v0.2.5 h1:puiw3/gK1WTEj9ZKnW00tAS0ex+ETqbLJ8juRuejA98=
|
||||
github.com/projectdiscovery/utils v0.2.5/go.mod h1:fv3WC6m/+bVT+wH+fMB+JsKviEC/UAuDSeKxWPlK3kk=
|
||||
github.com/projectdiscovery/utils v0.2.7 h1:XWdz7SscL++jqsnQ9ecHzSZE0RK33tyPcnqcXw+vmKs=
|
||||
github.com/projectdiscovery/utils v0.2.7/go.mod h1:N0N7tbdNFPegd9NpJ3onCPClaBrERcOIB88yww6UCF8=
|
||||
github.com/projectdiscovery/wappalyzergo v0.1.14 h1:nt1IM4RUmqeymsXk4h6BsZbKDoS2hjFvPkT2GaI1rz4=
|
||||
github.com/projectdiscovery/wappalyzergo v0.1.14/go.mod h1:/hzgxkBFTMe2wDbA93nFfoMjULw7/vIZ9QPSAnCgUa8=
|
||||
github.com/projectdiscovery/yamldoc-go v1.0.4 h1:eZoESapnMw6WAHiVgRwNqvbJEfNHEH148uthhFbG5jE=
|
||||
|
||||
@@ -256,6 +256,7 @@
|
||||
"deleteheader",
|
||||
"setbody",
|
||||
"waitevent",
|
||||
"waitdialog",
|
||||
"keyboard",
|
||||
"debug",
|
||||
"sleep",
|
||||
|
||||
@@ -31,7 +31,7 @@ const (
|
||||
CLIConfigFileName = "config.yaml"
|
||||
ReportingConfigFilename = "reporting-config.yaml"
|
||||
// Version is the current version of nuclei
|
||||
Version = `v3.3.1`
|
||||
Version = `v3.3.2`
|
||||
// Directory Names of custom templates
|
||||
CustomS3TemplatesDirName = "s3"
|
||||
CustomGitHubTemplatesDirName = "github"
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/fuzz/dataformat"
|
||||
"github.com/projectdiscovery/retryablehttp-go"
|
||||
"github.com/projectdiscovery/utils/maps"
|
||||
urlutil "github.com/projectdiscovery/utils/url"
|
||||
)
|
||||
|
||||
@@ -81,7 +82,7 @@ func (q *Path) Delete(key string) error {
|
||||
// Rebuild returns a new request with the
|
||||
// component rebuilt
|
||||
func (q *Path) Rebuild() (*retryablehttp.Request, error) {
|
||||
originalValues := make(map[string]interface{})
|
||||
originalValues := mapsutil.Map[string, any]{}
|
||||
splitted := strings.Split(q.req.URL.Path, "/")
|
||||
for i := range splitted {
|
||||
pathTillNow := strings.Join(splitted[:i+1], "/")
|
||||
@@ -95,8 +96,22 @@ func (q *Path) Rebuild() (*retryablehttp.Request, error) {
|
||||
lengthSplitted := len(q.value.parsed.Map)
|
||||
for i := lengthSplitted; i > 0; i-- {
|
||||
key := strconv.Itoa(i)
|
||||
original := originalValues[key].(string)
|
||||
new := q.value.parsed.Map[key].(string)
|
||||
|
||||
original, ok := originalValues.GetOrDefault(key, "").(string)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
new, ok := q.value.parsed.Map.GetOrDefault(key, "").(string)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
if new == original {
|
||||
// no need to replace
|
||||
continue
|
||||
}
|
||||
|
||||
originalPath = strings.Replace(originalPath, original, new, 1)
|
||||
}
|
||||
|
||||
|
||||
@@ -73,12 +73,22 @@ func (v *Value) SetParsed(data dataformat.KV, dataFormat string) {
|
||||
|
||||
// SetParsedValue sets the parsed value for a key
|
||||
// in the parsed map
|
||||
func (v *Value) SetParsedValue(key string, value string) bool {
|
||||
func (v *Value) SetParsedValue(key, value string) bool {
|
||||
if key == "" {
|
||||
return false
|
||||
}
|
||||
|
||||
origValue := v.parsed.Get(key)
|
||||
if origValue == nil {
|
||||
v.parsed.Set(key, value)
|
||||
return true
|
||||
}
|
||||
|
||||
// TODO(dwisiswant0): I'm sure that this can be simplified because
|
||||
// `dataformat.KV.*` is a type of `mapsutil.*` where the value is `any`. So,
|
||||
// it looks like we won't type conversion here or even have its own methods
|
||||
// inside `dataformat.KV`.
|
||||
|
||||
// If the value is a list, append to it
|
||||
// otherwise replace it
|
||||
switch v := origValue.(type) {
|
||||
|
||||
@@ -13,7 +13,7 @@ import (
|
||||
// if it's not important/significant (ex: json,xml) we use map
|
||||
// this also allows us to iteratively implement ordered map
|
||||
type KV struct {
|
||||
Map map[string]interface{}
|
||||
Map mapsutil.Map[string, any]
|
||||
OrderedMap *mapsutil.OrderedMap[string, any]
|
||||
}
|
||||
|
||||
|
||||
@@ -416,7 +416,7 @@ schemaLabel:
|
||||
return globalParams, nil
|
||||
}
|
||||
|
||||
// generateExampleFromSchema generates an example from a schema object
|
||||
// GenerateParameterFromSecurityScheme generates an example from a schema object
|
||||
func GenerateParameterFromSecurityScheme(scheme *openapi3.SecuritySchemeRef) (*openapi3.Parameter, error) {
|
||||
if !generic.EqualsAny(scheme.Value.Type, "http", "apiKey") {
|
||||
return nil, errorutil.NewWithTag("openapi", "unsupported security scheme type (%s) found in openapi file", scheme.Value.Type)
|
||||
|
||||
@@ -121,7 +121,7 @@ func NewInputProvider(opts InputOptions) (InputProvider, error) {
|
||||
}
|
||||
}
|
||||
|
||||
// SupportedFormats returns all supported input formats of nuclei
|
||||
// SupportedInputFormats returns all supported input formats of nuclei
|
||||
func SupportedInputFormats() string {
|
||||
return "list, " + http.SupportedFormats()
|
||||
}
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/dop251/goja"
|
||||
"github.com/kitabisa/go-ci"
|
||||
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/generators"
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/types"
|
||||
@@ -120,11 +121,17 @@ func (c *Compiler) ExecuteWithOptions(program *goja.Program, args *ExecuteArgs,
|
||||
defer cancel()
|
||||
// execute the script
|
||||
results, err := contextutil.ExecFuncWithTwoReturns(ctx, func() (val goja.Value, err error) {
|
||||
// TODO(dwisiswant0): remove this once we get the RCA.
|
||||
defer func() {
|
||||
if ci.IsCI() {
|
||||
return
|
||||
}
|
||||
|
||||
if r := recover(); r != nil {
|
||||
err = fmt.Errorf("panic: %v", r)
|
||||
}
|
||||
}()
|
||||
|
||||
return ExecuteProgram(program, args, opts)
|
||||
})
|
||||
if err != nil {
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"github.com/dop251/goja"
|
||||
"github.com/dop251/goja_nodejs/console"
|
||||
"github.com/dop251/goja_nodejs/require"
|
||||
"github.com/kitabisa/go-ci"
|
||||
"github.com/projectdiscovery/gologger"
|
||||
_ "github.com/projectdiscovery/nuclei/v3/pkg/js/generated/go/libbytes"
|
||||
_ "github.com/projectdiscovery/nuclei/v3/pkg/js/generated/go/libfs"
|
||||
@@ -84,11 +85,18 @@ func executeWithRuntime(runtime *goja.Runtime, p *goja.Program, args *ExecuteArg
|
||||
opts.Cleanup(runtime)
|
||||
}
|
||||
}()
|
||||
|
||||
// TODO(dwisiswant0): remove this once we get the RCA.
|
||||
defer func() {
|
||||
if ci.IsCI() {
|
||||
return
|
||||
}
|
||||
|
||||
if r := recover(); r != nil {
|
||||
err = fmt.Errorf("panic: %s", r)
|
||||
}
|
||||
}()
|
||||
|
||||
// set template ctx
|
||||
_ = runtime.Set("template", args.TemplateCtx)
|
||||
// set args
|
||||
|
||||
@@ -106,7 +106,7 @@ func (request *Request) ExecuteWithResults(input *contextargs.Context, metadata,
|
||||
}
|
||||
|
||||
func (request *Request) execute(input *contextargs.Context, domain string, metadata, previous output.InternalEvent, vars map[string]interface{}, callback protocols.OutputEventCallback) error {
|
||||
|
||||
var err error
|
||||
if vardump.EnableVarDump {
|
||||
gologger.Debug().Msgf("DNS Protocol request variables: \n%s\n", vardump.DumpVariables(vars))
|
||||
}
|
||||
@@ -199,7 +199,7 @@ func (request *Request) execute(input *contextargs.Context, domain string, metad
|
||||
}
|
||||
|
||||
callback(event)
|
||||
return nil
|
||||
return err
|
||||
}
|
||||
|
||||
func (request *Request) parseDNSInput(host string) (string, error) {
|
||||
|
||||
@@ -6,11 +6,15 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/invopop/jsonschema"
|
||||
mapsutil "github.com/projectdiscovery/utils/maps"
|
||||
)
|
||||
|
||||
// ActionType defines the action type for a browser action
|
||||
type ActionType int8
|
||||
|
||||
// ActionData stores the action output data
|
||||
type ActionData = mapsutil.Map[string, any]
|
||||
|
||||
// Types to be executed by the user.
|
||||
// name:ActionType
|
||||
const (
|
||||
@@ -68,6 +72,9 @@ const (
|
||||
// ActionWaitEvent waits for a specific event.
|
||||
// name:waitevent
|
||||
ActionWaitEvent
|
||||
// ActionWaitDialog waits for JavaScript dialog (alert, confirm, prompt, or onbeforeunload).
|
||||
// name:dialog
|
||||
ActionWaitDialog
|
||||
// ActionKeyboard performs a keyboard action event on a page.
|
||||
// name:keyboard
|
||||
ActionKeyboard
|
||||
@@ -104,6 +111,7 @@ var ActionStringToAction = map[string]ActionType{
|
||||
"deleteheader": ActionDeleteHeader,
|
||||
"setbody": ActionSetBody,
|
||||
"waitevent": ActionWaitEvent,
|
||||
"waitdialog": ActionWaitDialog,
|
||||
"keyboard": ActionKeyboard,
|
||||
"debug": ActionDebug,
|
||||
"sleep": ActionSleep,
|
||||
@@ -130,6 +138,7 @@ var ActionToActionString = map[ActionType]string{
|
||||
ActionDeleteHeader: "deleteheader",
|
||||
ActionSetBody: "setbody",
|
||||
ActionWaitEvent: "waitevent",
|
||||
ActionWaitDialog: "waitdialog",
|
||||
ActionKeyboard: "keyboard",
|
||||
ActionDebug: "debug",
|
||||
ActionSleep: "sleep",
|
||||
|
||||
@@ -45,7 +45,7 @@ type Options struct {
|
||||
}
|
||||
|
||||
// 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{})
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
|
||||
@@ -14,6 +14,7 @@ import (
|
||||
"github.com/go-rod/rod/lib/input"
|
||||
"github.com/go-rod/rod/lib/proto"
|
||||
"github.com/go-rod/rod/lib/utils"
|
||||
"github.com/kitabisa/go-ci"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/projectdiscovery/gologger"
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/contextargs"
|
||||
@@ -47,14 +48,19 @@ const (
|
||||
)
|
||||
|
||||
// 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) {
|
||||
outData = make(map[string]string)
|
||||
func (p *Page) ExecuteActions(input *contextargs.Context, actions []*Action, variables map[string]interface{}) (outData ActionData, err error) {
|
||||
outData = make(ActionData)
|
||||
// waitFuncs are function that needs to be executed after navigation
|
||||
// typically used for waitEvent
|
||||
waitFuncs := make([]func() error, 0)
|
||||
|
||||
// avoid any future panics caused due to go-rod library
|
||||
// TODO(dwisiswant0): remove this once we get the RCA.
|
||||
defer func() {
|
||||
if ci.IsCI() {
|
||||
return
|
||||
}
|
||||
|
||||
if r := recover(); r != nil {
|
||||
err = errorutil.New("panic on headless action: %v", r)
|
||||
}
|
||||
@@ -100,6 +106,8 @@ func (p *Page) ExecuteActions(input *contextargs.Context, actions []*Action, var
|
||||
if waitFunc != nil {
|
||||
waitFuncs = append(waitFuncs, waitFunc)
|
||||
}
|
||||
case ActionWaitDialog:
|
||||
err = p.HandleDialog(act, outData)
|
||||
case ActionFilesInput:
|
||||
if p.options.Options.AllowLocalFileAccess {
|
||||
err = p.FilesInput(act, outData)
|
||||
@@ -142,7 +150,7 @@ type rule struct {
|
||||
}
|
||||
|
||||
// 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)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Wrong timeout given")
|
||||
@@ -217,7 +225,7 @@ func geTimeParameter(p *Page, act *Action, parameterName string, defaultValue ti
|
||||
}
|
||||
|
||||
// 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")
|
||||
|
||||
args := make(map[string]string)
|
||||
@@ -228,7 +236,7 @@ func (p *Page) ActionAddHeader(act *Action, out map[string]string) error {
|
||||
}
|
||||
|
||||
// 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")
|
||||
|
||||
args := make(map[string]string)
|
||||
@@ -239,7 +247,7 @@ func (p *Page) ActionSetHeader(act *Action, out map[string]string) error {
|
||||
}
|
||||
|
||||
// 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")
|
||||
|
||||
args := make(map[string]string)
|
||||
@@ -249,7 +257,7 @@ func (p *Page) ActionDeleteHeader(act *Action, out map[string]string) error {
|
||||
}
|
||||
|
||||
// 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")
|
||||
|
||||
args := make(map[string]string)
|
||||
@@ -259,7 +267,7 @@ func (p *Page) ActionSetBody(act *Action, out map[string]string) error {
|
||||
}
|
||||
|
||||
// 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")
|
||||
|
||||
args := make(map[string]string)
|
||||
@@ -269,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.
|
||||
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
|
||||
// target <- is the url from template (ex: {{BaseURL}}/test)
|
||||
input, err := urlutil.Parse(p.input.MetaInput.Input)
|
||||
@@ -325,7 +333,7 @@ func (p *Page) NavigateURL(action *Action, out map[string]string, allvars map[st
|
||||
}
|
||||
|
||||
// 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")
|
||||
if code == "" {
|
||||
return errinvalidArguments
|
||||
@@ -346,7 +354,7 @@ func (p *Page) RunScript(action *Action, out map[string]string) error {
|
||||
}
|
||||
|
||||
// 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)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, errCouldNotGetElement)
|
||||
@@ -361,12 +369,12 @@ func (p *Page) ClickElement(act *Action, out map[string]string) error {
|
||||
}
|
||||
|
||||
// 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"))...)
|
||||
}
|
||||
|
||||
// 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)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, errCouldNotGetElement)
|
||||
@@ -381,7 +389,7 @@ func (p *Page) RightClickElement(act *Action, out map[string]string) error {
|
||||
}
|
||||
|
||||
// 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")
|
||||
if to == "" {
|
||||
to = ksuid.New().String()
|
||||
@@ -444,7 +452,7 @@ func (p *Page) Screenshot(act *Action, out map[string]string) error {
|
||||
}
|
||||
|
||||
// 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")
|
||||
if value == "" {
|
||||
return errinvalidArguments
|
||||
@@ -463,7 +471,7 @@ func (p *Page) InputElement(act *Action, out map[string]string) error {
|
||||
}
|
||||
|
||||
// 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")
|
||||
if value == "" {
|
||||
return errinvalidArguments
|
||||
@@ -486,7 +494,7 @@ func (p *Page) TimeInputElement(act *Action, out map[string]string) error {
|
||||
}
|
||||
|
||||
// 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")
|
||||
if value == "" {
|
||||
return errinvalidArguments
|
||||
@@ -511,7 +519,7 @@ func (p *Page) SelectInputElement(act *Action, out map[string]string) error {
|
||||
}
|
||||
|
||||
// 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)()
|
||||
|
||||
// Wait for the window.onload event and also wait for the network requests
|
||||
@@ -525,7 +533,7 @@ func (p *Page) WaitLoad(act *Action, out map[string]string) error {
|
||||
}
|
||||
|
||||
// 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)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, errCouldNotGetElement)
|
||||
@@ -541,7 +549,7 @@ func (p *Page) GetResource(act *Action, out map[string]string) error {
|
||||
}
|
||||
|
||||
// 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)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, errCouldNotGetElement)
|
||||
@@ -558,7 +566,7 @@ func (p *Page) FilesInput(act *Action, out map[string]string) error {
|
||||
}
|
||||
|
||||
// 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)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, errCouldNotGetElement)
|
||||
@@ -592,7 +600,7 @@ func (p *Page) ExtractElement(act *Action, out map[string]string) error {
|
||||
}
|
||||
|
||||
// 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")
|
||||
if event == "" {
|
||||
return nil, errors.New("event not recognized")
|
||||
@@ -630,6 +638,43 @@ func (p *Page) WaitEvent(act *Action, out map[string]string) (func() error, erro
|
||||
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.
|
||||
//
|
||||
// Supported values for by: r -> selector & regex, x -> xpath, js -> eval js,
|
||||
@@ -664,14 +709,14 @@ func (p *Page) pageElementBy(data map[string]string) (*rod.Element, error) {
|
||||
}
|
||||
|
||||
// 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.Trace(true)
|
||||
return nil
|
||||
}
|
||||
|
||||
// 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"]
|
||||
if seconds == "" {
|
||||
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}}}
|
||||
|
||||
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.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"}},
|
||||
}
|
||||
|
||||
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.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")
|
||||
@@ -77,7 +77,7 @@ func TestActionScript(t *testing.T) {
|
||||
{ActionType: ActionTypeHolder{ActionType: ActionWaitLoad}},
|
||||
{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.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")
|
||||
@@ -101,7 +101,7 @@ func TestActionClick(t *testing.T) {
|
||||
{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.Equal(t, "Nuclei Test Page", page.Page().MustInfo().Title, "could not navigate correctly")
|
||||
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
|
||||
}
|
||||
|
||||
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.Equal(t, "Nuclei Test Page", page.Page().MustInfo().Title, "could not navigate correctly")
|
||||
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"}},
|
||||
}
|
||||
|
||||
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.Equal(t, "Nuclei Test Page", page.Page().MustInfo().Title, "could not navigate correctly")
|
||||
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.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}},
|
||||
}
|
||||
|
||||
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.Equal(t, "Nuclei Test Page", page.Page().MustInfo().Title, "could not navigate correctly")
|
||||
_ = page.Page()
|
||||
@@ -233,7 +233,7 @@ func TestActionScreenshotToDir(t *testing.T) {
|
||||
{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.Equal(t, "Nuclei Test Page", page.Page().MustInfo().Title, "could not navigate correctly")
|
||||
_ = 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"}},
|
||||
}
|
||||
|
||||
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.Equal(t, "Nuclei Test Page", page.Page().MustInfo().Title, "could not navigate correctly")
|
||||
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"}},
|
||||
}
|
||||
|
||||
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")
|
||||
el := page.Page().MustElement("select")
|
||||
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"}},
|
||||
}
|
||||
|
||||
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.Equal(t, "Nuclei Test Page", page.Page().MustInfo().Title, "could not navigate correctly")
|
||||
el := page.Page().MustElement("input")
|
||||
@@ -337,7 +337,7 @@ func TestActionFilesInputNegative(t *testing.T) {
|
||||
}
|
||||
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")
|
||||
})
|
||||
}
|
||||
@@ -359,7 +359,7 @@ func TestActionWaitLoad(t *testing.T) {
|
||||
{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")
|
||||
el := page.Page().MustElement("button")
|
||||
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"},
|
||||
}
|
||||
|
||||
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.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"},
|
||||
}
|
||||
|
||||
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.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"}},
|
||||
}
|
||||
|
||||
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.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.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.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))
|
||||
}
|
||||
|
||||
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.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"}},
|
||||
}
|
||||
|
||||
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")
|
||||
el := page.Page().MustElement("input")
|
||||
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"}},
|
||||
}
|
||||
|
||||
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.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) {
|
||||
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")
|
||||
|
||||
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) {
|
||||
// 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.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()
|
||||
testHeadless(t, actions, timeout, func(w http.ResponseWriter, r *http.Request) {
|
||||
_, _ = fmt.Fprintln(w, response)
|
||||
}, 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()
|
||||
|
||||
lfa := getBoolFromEnv("LOCAL_FILE_ACCESS", true)
|
||||
|
||||
@@ -183,7 +183,13 @@ func (request *Request) executeRequestWithPayloads(input *contextargs.Context, p
|
||||
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
|
||||
request.options.AddTemplateVars(input.MetaInput, request.Type(), request.ID, outputEvent)
|
||||
if request.options.HasTemplateCtx(input.MetaInput) {
|
||||
|
||||
@@ -155,14 +155,14 @@ func (request *Request) executeOnTarget(input *contextargs.Context, visited maps
|
||||
}
|
||||
visited.Set(actualAddress, struct{}{})
|
||||
|
||||
if err := request.executeAddress(variables, actualAddress, address, input, kv.tls, previous, callback); err != nil {
|
||||
if err = request.executeAddress(variables, actualAddress, address, input, kv.tls, previous, callback); err != nil {
|
||||
outputEvent := request.responseToDSLMap("", "", "", address, "")
|
||||
callback(&output.InternalWrappedEvent{InternalEvent: outputEvent})
|
||||
gologger.Warning().Msgf("[%v] Could not make network request for (%s) : %s\n", request.options.TemplateID, actualAddress, err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
return nil
|
||||
return err
|
||||
}
|
||||
|
||||
// executeAddress executes the request for an address
|
||||
|
||||
@@ -86,7 +86,7 @@ func TestNetworkExecuteWithResults(t *testing.T) {
|
||||
err := request.ExecuteWithResults(ctxArgs, metadata, previous, func(event *output.InternalWrappedEvent) {
|
||||
finalEvent = event
|
||||
})
|
||||
require.Nil(t, err, "could not execute network request")
|
||||
require.NotNil(t, err, "could not execute network request")
|
||||
})
|
||||
require.Nil(t, finalEvent.Results, "could not get event output from request")
|
||||
|
||||
|
||||
@@ -52,6 +52,10 @@ func (s *ScanContext) Context() context.Context {
|
||||
return s.ctx
|
||||
}
|
||||
|
||||
func (s *ScanContext) GenerateErrorMessage() string {
|
||||
return joinErrors(s.errors)
|
||||
}
|
||||
|
||||
// GenerateResult returns final results slice from all events
|
||||
func (s *ScanContext) GenerateResult() []*output.ResultEvent {
|
||||
s.m.Lock()
|
||||
@@ -96,7 +100,7 @@ func (s *ScanContext) LogError(err error) {
|
||||
}
|
||||
s.errors = append(s.errors, err)
|
||||
|
||||
errorMessage := joinErrors(s.errors)
|
||||
errorMessage := s.GenerateErrorMessage()
|
||||
|
||||
for _, result := range s.results {
|
||||
result.Error = errorMessage
|
||||
|
||||
@@ -1612,6 +1612,7 @@ func init() {
|
||||
"deleteheader",
|
||||
"setbody",
|
||||
"waitevent",
|
||||
"dialog",
|
||||
"keyboard",
|
||||
"debug",
|
||||
"sleep",
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"github.com/dop251/goja"
|
||||
"github.com/projectdiscovery/gologger"
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/js/compiler"
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/operators"
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/operators/common/dsl"
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/output"
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/protocols"
|
||||
@@ -19,6 +20,8 @@ import (
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/tmplexec/flow"
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/tmplexec/generic"
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/tmplexec/multiproto"
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/types/nucleierr"
|
||||
"github.com/projectdiscovery/utils/errkit"
|
||||
)
|
||||
|
||||
// TemplateExecutor is an executor for a template
|
||||
@@ -126,6 +129,8 @@ func (e *TemplateExecuter) Execute(ctx *scan.ScanContext) (bool, error) {
|
||||
executed := &atomic.Bool{}
|
||||
// matched in this case means something was exported / written to output
|
||||
matched := &atomic.Bool{}
|
||||
// callbackCalled tracks if the callback was called or not
|
||||
callbackCalled := &atomic.Bool{}
|
||||
defer func() {
|
||||
// it is essential to remove template context of `Scan i.e template x input pair`
|
||||
// since it is of no use after scan is completed (regardless of success or failure)
|
||||
@@ -143,6 +148,7 @@ func (e *TemplateExecuter) Execute(ctx *scan.ScanContext) (bool, error) {
|
||||
}
|
||||
|
||||
ctx.OnResult = func(event *output.InternalWrappedEvent) {
|
||||
callbackCalled.Store(true)
|
||||
if event == nil {
|
||||
// something went wrong
|
||||
return
|
||||
@@ -198,13 +204,64 @@ func (e *TemplateExecuter) Execute(ctx *scan.ScanContext) (bool, error) {
|
||||
} else {
|
||||
errx = e.engine.ExecuteWithResults(ctx)
|
||||
}
|
||||
ctx.LogError(errx)
|
||||
|
||||
if lastMatcherEvent != nil {
|
||||
lastMatcherEvent.InternalEvent["error"] = tryParseCause(fmt.Errorf("%s", ctx.GenerateErrorMessage()))
|
||||
writeFailureCallback(lastMatcherEvent, e.options.Options.MatcherStatus)
|
||||
}
|
||||
|
||||
//TODO: this is a hacky way to handle the case where the callback is not called and matcher-status is true.
|
||||
// This is a workaround and needs to be refactored.
|
||||
// Check if callback was never called and matcher-status is true
|
||||
if !callbackCalled.Load() && e.options.Options.MatcherStatus {
|
||||
fakeEvent := &output.InternalWrappedEvent{
|
||||
Results: []*output.ResultEvent{
|
||||
{
|
||||
TemplateID: e.options.TemplateID,
|
||||
Info: e.options.TemplateInfo,
|
||||
Type: e.getTemplateType(),
|
||||
Host: ctx.Input.MetaInput.Input,
|
||||
Error: tryParseCause(fmt.Errorf("%s", ctx.GenerateErrorMessage())),
|
||||
},
|
||||
},
|
||||
OperatorsResult: &operators.Result{
|
||||
Matched: false,
|
||||
},
|
||||
}
|
||||
writeFailureCallback(fakeEvent, e.options.Options.MatcherStatus)
|
||||
}
|
||||
|
||||
return executed.Load() || matched.Load(), errx
|
||||
}
|
||||
|
||||
// tryParseCause tries to parse the cause of given error
|
||||
// this is legacy support due to use of errorutil in existing libraries
|
||||
// but this should not be required once all libraries are updated
|
||||
func tryParseCause(err error) string {
|
||||
errStr := ""
|
||||
errX := errkit.FromError(err)
|
||||
if errX != nil {
|
||||
var errCause error
|
||||
|
||||
if len(errX.Errors()) > 1 {
|
||||
errCause = errX.Errors()[0]
|
||||
}
|
||||
if errCause == nil {
|
||||
errCause = errX
|
||||
}
|
||||
|
||||
msg := strings.Trim(errCause.Error(), "{} ")
|
||||
parts := strings.Split(msg, ":")
|
||||
errCause = errkit.New("%s", parts[len(parts)-1])
|
||||
errKind := errkit.GetErrorKind(err, nucleierr.ErrTemplateLogic).String()
|
||||
errStr = errCause.Error()
|
||||
errStr = strings.TrimSpace(strings.Replace(errStr, "errKind="+errKind, "", -1))
|
||||
}
|
||||
|
||||
return errStr
|
||||
}
|
||||
|
||||
// ExecuteWithResults executes the protocol requests and returns results instead of writing them.
|
||||
func (e *TemplateExecuter) ExecuteWithResults(ctx *scan.ScanContext) ([]*output.ResultEvent, error) {
|
||||
var errx error
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/scan"
|
||||
templateTypes "github.com/projectdiscovery/nuclei/v3/pkg/templates/types"
|
||||
|
||||
"github.com/kitabisa/go-ci"
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/types"
|
||||
errorutil "github.com/projectdiscovery/utils/errors"
|
||||
fileutil "github.com/projectdiscovery/utils/file"
|
||||
@@ -201,7 +202,13 @@ func (f *FlowExecutor) ExecuteWithResults(ctx *scan.ScanContext) error {
|
||||
}
|
||||
|
||||
}()
|
||||
|
||||
// TODO(dwisiswant0): remove this once we get the RCA.
|
||||
defer func() {
|
||||
if ci.IsCI() {
|
||||
return
|
||||
}
|
||||
|
||||
if r := recover(); r != nil {
|
||||
f.ctx.LogError(fmt.Errorf("panic occurred while executing flow: %v", r))
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user