diff --git a/.github/auto_assign.yml b/.github/auto_assign.yml new file mode 100644 index 000000000..273b6ac02 --- /dev/null +++ b/.github/auto_assign.yml @@ -0,0 +1,9 @@ +addReviewers: true +reviewers: + - dogancanbakir + - dwisiswant0 + - mzack9999 + +numberOfReviewers: 1 +skipKeywords: + - '@dependabot' \ No newline at end of file diff --git a/.github/workflows/stale.yaml b/.github/workflows/stale.yaml index 636d20d75..5254b32a0 100644 --- a/.github/workflows/stale.yaml +++ b/.github/workflows/stale.yaml @@ -1,21 +1,41 @@ -name: 'Close stale issues and PR' +name: 💤 Stale + on: schedule: - - cron: '30 1 * * *' + - cron: "0 0 * * 0" # Weekly jobs: stale: runs-on: ubuntu-latest + permissions: + actions: write + contents: write # only for delete-branch option + issues: write + pull-requests: write steps: - uses: actions/stale@v9 with: - only-labels: "Status: Abandoned, Type: Question" - stale-issue-label: stale - stale-issue-message: 'This issue is stale because it has been open 14 days with no activity. Remove stale label or comment or this will be closed in 90 days.' - close-issue-message: 'This issue was closed because it has been stalled for 90 days with no activity.' - days-before-stale: 14 - days-before-close: 90 - days-before-pr-stale: -1 - days-before-pr-close: -1 - stale-pr-message: '' - close-pr-message: '' \ No newline at end of file + days-before-stale: 90 + days-before-close: 7 + stale-issue-label: "Status: Stale" + stale-pr-label: "Status: Stale" + stale-issue-message: > + This issue has been automatically marked as stale because it has not + had recent activity. It will be closed in 7 days if no further + activity occurs. Thank you for your contributions! + stale-pr-message: > + This pull request has been automatically marked as stale due to + inactivity. It will be closed in 7 days if no further activity + occurs. Please update if you wish to keep it open. + close-issue-message: > + This issue has been automatically closed due to inactivity. If you + think this is a mistake or would like to continue the discussion, + please comment or feel free to reopen it. + close-pr-message: > + This pull request has been automatically closed due to inactivity. + If you think this is a mistake or would like to continue working on + it, please comment or feel free to reopen it. + close-issue-label: "Status: Abandoned" + close-pr-label: "Status: Abandoned" + exempt-issue-labels: "Status: Abandoned" + exempt-pr-labels: "Status: Abandoned" diff --git a/.goreleaser.yml b/.goreleaser.yml index 852f6cb52..0ea247b09 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -27,7 +27,8 @@ builds: main: cmd/httpx/httpx.go archives: -- format: zip +- formats: + - zip name_template: '{{ .ProjectName }}_{{ .Version }}_{{ if eq .Os "darwin" }}macOS{{ else }}{{ .Os }}{{ end }}_{{ .Arch }}' checksum: @@ -42,4 +43,4 @@ announce: discord: enabled: true - message_template: '**New Release: {{ .ProjectName }} {{.Tag}}** is published! Check it out at {{ .ReleaseURL }}' \ No newline at end of file + message_template: '**New Release: {{ .ProjectName }} {{.Tag}}** is published! Check it out at {{ .ReleaseURL }}' diff --git a/README.md b/README.md index efc17d8fb..c7017878c 100644 --- a/README.md +++ b/README.md @@ -62,7 +62,7 @@ # Installation Instructions -`httpx` requires **go1.21** to install successfully. Run the following command to get the repo: +`httpx` requires **go >=1.24.0** to install successfully. Run the following command to get the repo: ```sh go install -v github.com/projectdiscovery/httpx/cmd/httpx@latest @@ -85,10 +85,6 @@ This will display help for the tool. Here are all the switches it supports. ```console -Usage: - ./httpx [flags] - -Flags: httpx is a fast and multi-purpose HTTP toolkit that allows running multiple probes using the retryablehttp library. Usage: @@ -115,8 +111,9 @@ PROBES: -bp, -body-preview display first N characters of response body (default 100) -server, -web-server display server name -td, -tech-detect display technology in use based on wappalyzer dataset + -cff, -custom-fingerprint-file string path to a custom fingerprint file for technology detection -method display http request method - -websocket display server using websocket + -ws, -websocket display server using websocket -ip display host ip -cname display host cname -extract-fqdn, -efqdn get domain and subdomains from response body and header in jsonl/csv output @@ -133,6 +130,7 @@ HEADLESS: -ehb, -exclude-headless-body enable excluding headless header from json output -st, -screenshot-timeout value set timeout for screenshot in seconds (default 10s) -sid, -screenshot-idle value set idle time before taking screenshot in seconds (default 1s) + -jsc, -javascript-code string[] execute JavaScript code after navigation MATCHERS: -mc, -match-code string match response with specified status code (-mc 200,302) @@ -203,6 +201,8 @@ OUTPUT: -svrc, -store-vision-recon-cluster include visual recon clusters (-ss and -sr only) -pr, -protocol string protocol to use (unknown, http11) -fepp, -filter-error-page-path string path to store filtered error pages (default "filtered_error_page.json") + -lof, -list-output-fields list available output field names for filtering + -eof, -exclude-output-fields string[] exclude specified output fields from results CONFIGURATIONS: -config string path to the httpx configuration file (default $HOME/.config/httpx/config.yaml) @@ -211,6 +211,7 @@ CONFIGURATIONS: -deny string[] denied list of IP/CIDR's to process (file or comma separated) -sni, -sni-name string custom TLS SNI name -random-agent enable Random User-Agent to use (default true) + -auto-referer set the Referer header to the current URL (default false) -H, -header string[] custom http headers to send with request -http-proxy, -proxy string http proxy to use (eg http://127.0.0.1:8080) -unsafe send raw requests skipping golang normalization diff --git a/cmd/functional-test/main.go b/cmd/functional-test/main.go index 3fd4242a5..1500ec61a 100644 --- a/cmd/functional-test/main.go +++ b/cmd/functional-test/main.go @@ -41,7 +41,9 @@ func runFunctionalTests() error { if err != nil { return errors.Wrap(err, "could not open test cases") } - defer file.Close() + defer func() { + _ = file.Close() + }() scanner := bufio.NewScanner(file) for scanner.Scan() { diff --git a/cmd/httpx/httpx.go b/cmd/httpx/httpx.go index 77e060584..77e54f4c4 100644 --- a/cmd/httpx/httpx.go +++ b/cmd/httpx/httpx.go @@ -106,9 +106,6 @@ func setupOptionalAssetUpload(opts *runner.Options) *pdcp.UploadWriter { } return nil } - if opts.Screenshot { - gologger.Fatal().Msgf("Screenshot option is not supported for dashboard upload yet") - } gologger.Info().Msgf("To view results in UI dashboard, visit https://cloud.projectdiscovery.io/assets upon completion.") h := &pdcpauth.PDCPCredHandler{} creds, err := h.GetCreds() @@ -131,10 +128,11 @@ func setupOptionalAssetUpload(opts *runner.Options) *pdcp.UploadWriter { opts.OnClose = func() { writer.Close() } + // add additional metadata if opts.AssetID != "" { // silently ignore - _ = writer.SetAssetID(opts.AssetID) + writer.SetAssetID(opts.AssetID) } if opts.AssetName != "" { // silently ignore diff --git a/cmd/integration-test/http.go b/cmd/integration-test/http.go index caa14480a..101799739 100644 --- a/cmd/integration-test/http.go +++ b/cmd/integration-test/http.go @@ -49,7 +49,7 @@ type standardHttpGet struct { func (h *standardHttpGet) Execute() error { router := httprouter.New() router.GET("/", httprouter.Handle(func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { - fmt.Fprintf(w, "This is a test") + _, _ = fmt.Fprintf(w, "This is a test") r.Close = true })) var ts *httptest.Server @@ -100,7 +100,7 @@ func (h *issue276) Execute() error { router.GET("/redirect", httprouter.Handle(func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { w.Header().Add("Location", ts.URL+"/redirect") w.WriteHeader(302) - fmt.Fprintf(w, "Object moved") + _, _ = fmt.Fprintf(w, "Object moved") })) ts = httptest.NewServer(router) defer ts.Close() @@ -163,7 +163,7 @@ func (h *issue303) Execute() error { // mimic a misconfigured web server behavior declaring gzip body w.Header().Add("Content-Encoding", "gzip") // but sending it uncompressed - fmt.Fprint(w, "This is a test") + _, _ = fmt.Fprint(w, "This is a test") })) ts = httptest.NewServer(router) defer ts.Close() @@ -191,7 +191,7 @@ func (h *issue363) Execute() error { router.GET("/redirect", httprouter.Handle(func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { w.Header().Add("Location", ts.URL+"/redirect") w.WriteHeader(302) - fmt.Fprintf(w, "Object moved") + _, _ = fmt.Fprintf(w, "Object moved") })) ts = httptest.NewServer(router) defer ts.Close() @@ -214,7 +214,7 @@ func (h *issue400) Execute() error { router.POST("/receive", httprouter.Handle(func(w http.ResponseWriter, r *http.Request, p httprouter.Params) { w.Header().Add("Content-Type", "application/json") data, _ := io.ReadAll(r.Body) - fmt.Fprintf(w, "data received %s", data) + _, _ = fmt.Fprintf(w, "data received %s", data) })) ts = httptest.NewServer(router) defer ts.Close() @@ -238,7 +238,7 @@ func (h *issue414) Execute() error { router.POST(uripath, httprouter.Handle(func(w http.ResponseWriter, r *http.Request, p httprouter.Params) { w.Header().Add("Content-Type", "application/json") data, _ := io.ReadAll(r.Body) - fmt.Fprintf(w, "data received %s", data) + _, _ = fmt.Fprintf(w, "data received %s", data) })) ts = httptest.NewServer(router) defer ts.Close() @@ -265,7 +265,7 @@ func (h *titleUnwantedChars) Execute() error { uriPath := "/index" router.GET(uriPath, httprouter.Handle(func(w http.ResponseWriter, r *http.Request, p httprouter.Params) { htmlResponse := "\v\fProject\n\r Discovery\n - Httpx\t>test data" - fmt.Fprint(w, htmlResponse) + _, _ = fmt.Fprint(w, htmlResponse) })) ts = httptest.NewServer(router) defer ts.Close() @@ -290,7 +290,7 @@ func (h *issue480) Execute() error { uriPath := "////////////////../../../../../../../../etc/passwd" router.GET(uriPath, httprouter.Handle(func(w http.ResponseWriter, r *http.Request, p httprouter.Params) { htmlResponse := "ok from uri" - fmt.Fprint(w, htmlResponse) + _, _ = fmt.Fprint(w, htmlResponse) })) ts = httptest.NewServer(router) defer ts.Close() @@ -314,7 +314,7 @@ func (h *customHeader) Execute() error { router := httprouter.New() router.GET("/", httprouter.Handle(func(w http.ResponseWriter, r *http.Request, p httprouter.Params) { w.Header().Add("Content-Type", "application/json") - fmt.Fprint(w, `{"status": "ok"}`) + _, _ = fmt.Fprint(w, `{"status": "ok"}`) })) ts = httptest.NewServer(router) defer ts.Close() @@ -341,7 +341,7 @@ func (h *outputMatchCondition) Execute() error { router.GET("/", httprouter.Handle(func(w http.ResponseWriter, r *http.Request, p httprouter.Params) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(200) - fmt.Fprint(w, `{"status": "ok"}`) + _, _ = fmt.Fprint(w, `{"status": "ok"}`) })) ts = httptest.NewServer(router) defer ts.Close() @@ -365,7 +365,7 @@ func (h *outputFilterCondition) Execute() error { router.GET("/", httprouter.Handle(func(w http.ResponseWriter, r *http.Request, p httprouter.Params) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(200) - fmt.Fprint(w, `{"status": "ok"}`) + _, _ = fmt.Fprint(w, `{"status": "ok"}`) })) ts = httptest.NewServer(router) defer ts.Close() @@ -390,7 +390,7 @@ func (h *outputAll) Execute() error { router.GET("/", httprouter.Handle(func(w http.ResponseWriter, r *http.Request, p httprouter.Params) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(200) - fmt.Fprint(w, `{"status": "ok"}`) + _, _ = fmt.Fprint(w, `{"status": "ok"}`) })) ts = httptest.NewServer(router) defer ts.Close() diff --git a/cmd/integration-test/library.go b/cmd/integration-test/library.go index 059fa4119..afecc0a19 100644 --- a/cmd/integration-test/library.go +++ b/cmd/integration-test/library.go @@ -22,7 +22,9 @@ func (h *httpxLibrary) Execute() error { if err != nil { return err } - defer os.RemoveAll(testFile) + defer func() { + _ = os.RemoveAll(testFile) + }() var got string @@ -64,7 +66,9 @@ func (h *httpxLibraryWithStream) Execute() error { if err != nil { return err } - defer os.RemoveAll(testFile) + defer func() { + _ = os.RemoveAll(testFile) + }() var got string diff --git a/common/customports/customport.go b/common/customports/customport.go index 9a08defb2..0e9e5d322 100644 --- a/common/customports/customport.go +++ b/common/customports/customport.go @@ -77,14 +77,14 @@ func (c *CustomPorts) Set(value string) error { } highP, err := strconv.Atoi(potentialRange[1]) if err != nil { - return errors.Wrap(err, fmt.Sprintf("Could not cast last port of your port range(%s) to integer from your value: %s", potentialPort, potentialRange[1])) + return errors.Wrap(err, fmt.Sprintf("could not cast last port of your port range(%s) to integer from your value: %s", potentialPort, potentialRange[1])) } if err := checkPortValue(highP); err != nil { return errors.Wrap(err, fmt.Sprintf("last port of your range(%d)", lowP)) } if lowP > highP { - return fmt.Errorf("First value of port range should be lower than the last port from your range: [%d, %d]", lowP, highP) + return fmt.Errorf("first value of port range should be lower than the last port from your range: [%d, %d]", lowP, highP) } for i := lowP; i <= highP; i++ { diff --git a/common/httpx/httpx.go b/common/httpx/httpx.go index 256066b2b..1b75ee811 100644 --- a/common/httpx/httpx.go +++ b/common/httpx/httpx.go @@ -155,7 +155,7 @@ func New(options *Options) (*HTTPX, error) { if httpx.Options.Protocol == "http11" { // disable http2 - os.Setenv("GODEBUG", "http2client=0") + _ = os.Setenv("GODEBUG", "http2client=0") transport.TLSNextProto = map[string]func(string, *tls.Conn) http.RoundTripper{} } @@ -359,7 +359,7 @@ func (h *HTTPX) getResponse(req *retryablehttp.Request, unsafeOptions UnsafeOpti func (h *HTTPX) doUnsafeWithOptions(req *retryablehttp.Request, unsafeOptions UnsafeOptions) (*http.Response, error) { method := req.Method headers := req.Header - targetURL := req.URL.String() + targetURL := req.String() body := req.Body options := rawhttp.DefaultOptions options.Timeout = h.Options.Timeout @@ -424,6 +424,9 @@ func (h *HTTPX) SetCustomHeaders(r *retryablehttp.Request, headers map[string]st switch strings.ToLower(name) { case "host": r.Host = value + if h.Options.Unsafe { + r.Header.Set("Host", value) + } case "cookie": // cookies are set in the default branch, and reset during the follow redirect flow fallthrough @@ -435,6 +438,9 @@ func (h *HTTPX) SetCustomHeaders(r *retryablehttp.Request, headers map[string]st userAgent := useragent.PickRandom() r.Header.Set("User-Agent", userAgent.Raw) //nolint } + if h.Options.AutoReferer && r.Header.Get("Referer") == "" { + r.Header.Set("Referer", r.String()) + } } func (httpx *HTTPX) setCustomCookies(req *http.Request) { @@ -448,7 +454,7 @@ func (httpx *HTTPX) setCustomCookies(req *http.Request) { func (httpx *HTTPX) Sanitize(respStr string, trimLine, normalizeSpaces bool) string { respStr = httpx.htmlPolicy.Sanitize(respStr) if trimLine { - respStr = strings.Replace(respStr, "\n", "", -1) + respStr = strings.ReplaceAll(respStr, "\n", "") } if normalizeSpaces { respStr = httputilz.NormalizeSpaces(respStr) diff --git a/common/httpx/option.go b/common/httpx/option.go index 6386213bb..b64cfd390 100644 --- a/common/httpx/option.go +++ b/common/httpx/option.go @@ -12,6 +12,7 @@ import ( // Options contains configuration options for the client type Options struct { RandomAgent bool + AutoReferer bool DefaultUserAgent string Proxy string // Deprecated: use Proxy diff --git a/common/pagetypeclassifier/pagetypeclassifier.go b/common/pagetypeclassifier/pagetypeclassifier.go index 67eb3e09a..a1a870bf2 100644 --- a/common/pagetypeclassifier/pagetypeclassifier.go +++ b/common/pagetypeclassifier/pagetypeclassifier.go @@ -3,7 +3,7 @@ package pagetypeclassifier import ( _ "embed" - "github.com/jaytaylor/html2text" + htmltomarkdown "github.com/JohannesKaufmann/html-to-markdown/v2" "github.com/projectdiscovery/utils/ml/naive_bayes" ) @@ -31,7 +31,7 @@ func (n *PageTypeClassifier) Classify(html string) string { } func htmlToText(html string) string { - text, err := html2text.FromString(html, html2text.Options{TextOnly: true}) + text, err := htmltomarkdown.ConvertString(html) if err != nil { panic(err) } diff --git a/examples/speed_control/main.go b/examples/speed_control/main.go index 5e34f6a71..ae3d4dde3 100644 --- a/examples/speed_control/main.go +++ b/examples/speed_control/main.go @@ -60,7 +60,9 @@ func main() { if err != nil { log.Fatalf("Error sending PUT request: %v", err) } - defer resp.Body.Close() + defer func() { + _ = resp.Body.Close() + }() if resp.StatusCode != http.StatusOK { log.Printf("Failed to update threads, status code: %d", resp.StatusCode) diff --git a/go.mod b/go.mod index c370e6cd6..b01138953 100644 --- a/go.mod +++ b/go.mod @@ -9,57 +9,58 @@ require ( github.com/PuerkitoBio/goquery v1.10.3 github.com/akrylysov/pogreb v0.10.2 // indirect github.com/corona10/goimagehash v1.1.0 - github.com/go-faker/faker/v4 v4.6.1 + github.com/go-faker/faker/v4 v4.7.0 github.com/go-rod/rod v0.116.2 github.com/golang/snappy v0.0.4 // indirect github.com/hbakhtiyor/strsim v0.0.0-20190107154042-4d2bbb273edf github.com/hdm/jarm-go v0.0.7 - github.com/jaytaylor/html2text v0.0.0-20230321000545-74c2419ad056 github.com/julienschmidt/httprouter v1.3.0 github.com/logrusorgru/aurora v2.0.3+incompatible github.com/mfonda/simhash v0.0.0-20151007195837-79f94a1100d6 github.com/microcosm-cc/bluemonday v1.0.27 - github.com/miekg/dns v1.1.62 // indirect + github.com/miekg/dns v1.1.68 // indirect github.com/pkg/errors v0.9.1 github.com/projectdiscovery/asnmap v1.1.1 - github.com/projectdiscovery/cdncheck v1.1.28 + github.com/projectdiscovery/cdncheck v1.2.9 github.com/projectdiscovery/clistats v0.1.1 - github.com/projectdiscovery/dsl v0.5.0 - github.com/projectdiscovery/fastdialer v0.4.2 + github.com/projectdiscovery/dsl v0.8.4 + github.com/projectdiscovery/fastdialer v0.4.15 github.com/projectdiscovery/fdmax v0.0.4 github.com/projectdiscovery/goconfig v0.0.1 github.com/projectdiscovery/goflags v0.1.74 - github.com/projectdiscovery/gologger v1.1.54 - github.com/projectdiscovery/hmap v0.0.91 - github.com/projectdiscovery/mapcidr v1.1.34 - github.com/projectdiscovery/networkpolicy v0.1.18 - github.com/projectdiscovery/ratelimit v0.0.81 + github.com/projectdiscovery/gologger v1.1.59 + github.com/projectdiscovery/hmap v0.0.95 + github.com/projectdiscovery/mapcidr v1.1.97 + github.com/projectdiscovery/networkpolicy v0.1.27 + github.com/projectdiscovery/ratelimit v0.0.82 github.com/projectdiscovery/rawhttp v0.1.90 - github.com/projectdiscovery/retryablehttp-go v1.0.118 - github.com/projectdiscovery/tlsx v1.2.0 - github.com/projectdiscovery/useragent v0.0.101 - github.com/projectdiscovery/utils v0.4.22 - github.com/projectdiscovery/wappalyzergo v0.2.38 + github.com/projectdiscovery/retryablehttp-go v1.0.131 + github.com/projectdiscovery/tlsx v1.2.1 + github.com/projectdiscovery/useragent v0.0.102 + github.com/projectdiscovery/utils v0.6.1-0.20251030144701-ce5c4b44e1e6 + github.com/projectdiscovery/wappalyzergo v0.2.54 github.com/rs/xid v1.6.0 github.com/spaolacci/murmur3 v1.1.0 - github.com/stretchr/testify v1.10.0 + github.com/stretchr/testify v1.11.1 github.com/zmap/zcrypto v0.0.0-20240512203510-0fef58d9a9db go.etcd.io/bbolt v1.4.0 // indirect go.uber.org/multierr v1.11.0 - golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8 - golang.org/x/net v0.42.0 - golang.org/x/sys v0.34.0 // indirect - golang.org/x/text v0.27.0 + golang.org/x/exp v0.0.0-20250911091902-df9299821621 + golang.org/x/net v0.46.0 + golang.org/x/sys v0.37.0 // indirect + golang.org/x/text v0.30.0 ) require ( + github.com/JohannesKaufmann/html-to-markdown/v2 v2.4.0 github.com/go-viper/mapstructure/v2 v2.4.0 github.com/gocarina/gocsv v0.0.0-20240520201108-78e41c74b4b1 - github.com/weppos/publicsuffix-go v0.40.3-0.20250408071509-6074bbe7fd39 + github.com/weppos/publicsuffix-go v0.50.0 ) require ( aead.dev/minisign v0.2.0 // indirect + github.com/JohannesKaufmann/dom v0.2.0 // indirect github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible // indirect github.com/Masterminds/semver/v3 v3.2.1 // indirect github.com/Mzack9999/go-http-digest-auth-client v0.6.1-0.20220414142836-eb8883508809 // indirect @@ -74,13 +75,14 @@ require ( github.com/bodgit/plumbing v1.3.0 // indirect github.com/bodgit/sevenzip v1.6.0 // indirect github.com/bodgit/windows v1.0.1 // indirect + github.com/brianvoe/gofakeit/v7 v7.2.1 // indirect github.com/charmbracelet/glamour v0.8.0 // indirect github.com/charmbracelet/lipgloss v0.13.0 // indirect github.com/charmbracelet/x/ansi v0.3.2 // indirect github.com/cheggaaa/pb/v3 v3.1.6 // indirect github.com/cloudflare/cfssl v1.6.4 // indirect github.com/cloudflare/circl v1.6.1 // indirect - github.com/cnf/structhash v0.0.0-20201127153200-e1b16c1ebc08 // indirect + github.com/cnf/structhash v0.0.0-20250313080605-df4c6cc74a9a // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/dimchansky/utfbom v1.1.1 // indirect github.com/dlclark/regexp2 v1.11.5 // indirect @@ -88,7 +90,7 @@ require ( github.com/dsnet/compress v0.0.2-0.20230904184137-39efe44ab707 // indirect github.com/fatih/color v1.18.0 // indirect github.com/felixge/fgprof v0.9.5 // indirect - github.com/gaissmai/bart v0.20.5 // indirect + github.com/gaissmai/bart v0.26.0 // indirect github.com/go-ole/go-ole v1.2.6 // indirect github.com/google/certificate-transparency-go v1.3.2 // indirect github.com/google/go-github/v30 v30.1.0 // indirect @@ -97,10 +99,13 @@ require ( github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect github.com/google/uuid v1.6.0 // indirect github.com/gorilla/css v1.0.1 // indirect + github.com/gosimple/slug v1.15.0 // indirect + github.com/gosimple/unidecode v1.0.1 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/go-version v1.6.0 // indirect github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect + github.com/iangcarroll/cookiemonster v1.6.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/kataras/jwt v0.1.10 // indirect github.com/klauspost/compress v1.17.11 // indirect @@ -116,10 +121,9 @@ require ( github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/muesli/reflow v0.3.0 // indirect - github.com/muesli/termenv v0.15.3-0.20240618155329-98d742f6907a // indirect + github.com/muesli/termenv v0.16.0 // indirect github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect - github.com/nwaples/rardecode/v2 v2.0.0-beta.4.0.20241112120701-034e449c6e78 // indirect - github.com/olekukonko/tablewriter v0.0.5 // indirect + github.com/nwaples/rardecode/v2 v2.2.0 // indirect github.com/pierrec/lz4/v4 v4.1.21 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect @@ -127,7 +131,7 @@ require ( github.com/projectdiscovery/freeport v0.0.7 // indirect github.com/projectdiscovery/gostruct v0.0.2 // indirect github.com/projectdiscovery/machineid v0.0.0-20240226150047-2e2c51e35983 // indirect - github.com/projectdiscovery/retryabledns v1.0.103 // indirect + github.com/projectdiscovery/retryabledns v1.0.108 // indirect github.com/refraction-networking/utls v1.7.1 // indirect github.com/rivo/uniseg v0.4.7 // indirect github.com/rogpeppe/go-internal v1.12.0 // indirect @@ -136,38 +140,38 @@ require ( github.com/shirou/gopsutil/v3 v3.24.2 // indirect github.com/shoenig/go-m1cpu v0.1.6 // indirect github.com/sorairolake/lzip-go v0.3.5 // indirect - github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf // indirect github.com/syndtr/goleveldb v1.0.0 // indirect github.com/therootcompany/xz v1.0.1 // indirect github.com/tidwall/btree v1.7.0 // indirect github.com/tidwall/buntdb v1.3.1 // indirect github.com/tidwall/gjson v1.18.0 // indirect github.com/tidwall/grect v0.1.4 // indirect - github.com/tidwall/match v1.1.1 // indirect + github.com/tidwall/match v1.2.0 // indirect github.com/tidwall/pretty v1.2.1 // indirect github.com/tidwall/rtred v0.1.2 // indirect github.com/tidwall/tinyqueue v0.1.1 // indirect github.com/tklauser/go-sysconf v0.3.12 // indirect github.com/tklauser/numcpus v0.6.1 // indirect - github.com/ulikunitz/xz v0.5.12 // indirect + github.com/ulikunitz/xz v0.5.15 // indirect + github.com/xdg-go/pbkdf2 v1.0.0 // indirect github.com/ysmood/fetchup v0.2.3 // indirect github.com/ysmood/goob v0.4.0 // indirect github.com/ysmood/got v0.40.0 // indirect github.com/ysmood/gson v0.7.3 // indirect github.com/ysmood/leakless v0.9.0 // indirect - github.com/yuin/goldmark v1.7.4 // indirect + github.com/yuin/goldmark v1.7.13 // indirect github.com/yuin/goldmark-emoji v1.0.3 // indirect github.com/yusufpapurcu/wmi v1.2.4 // indirect github.com/zcalusic/sysinfo v1.0.2 // indirect github.com/zmap/rc2 v0.0.0-20190804163417-abaa70531248 // indirect go4.org v0.0.0-20230225012048-214862532bf5 // indirect - golang.org/x/crypto v0.40.0 // indirect - golang.org/x/mod v0.25.0 // indirect + golang.org/x/crypto v0.43.0 // indirect + golang.org/x/mod v0.28.0 // indirect golang.org/x/oauth2 v0.28.0 // indirect - golang.org/x/sync v0.16.0 // indirect - golang.org/x/term v0.33.0 // indirect + golang.org/x/sync v0.17.0 // indirect + golang.org/x/term v0.36.0 // indirect golang.org/x/time v0.11.0 // indirect - golang.org/x/tools v0.34.0 // indirect + golang.org/x/tools v0.37.0 // indirect gopkg.in/djherbis/times.v1 v1.3.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index cb4321f96..7824b8c17 100644 --- a/go.sum +++ b/go.sum @@ -20,6 +20,10 @@ cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0Zeo dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/JohannesKaufmann/dom v0.2.0 h1:1bragmEb19K8lHAqgFgqCpiPCFEZMTXzOIEjuxkUfLQ= +github.com/JohannesKaufmann/dom v0.2.0/go.mod h1:57iSUl5RKric4bUkgos4zu6Xt5LMHUnw3TF1l5CbGZo= +github.com/JohannesKaufmann/html-to-markdown/v2 v2.4.0 h1:C0/TerKdQX9Y9pbYi1EsLr5LDNANsqunyI/btpyfCg8= +github.com/JohannesKaufmann/html-to-markdown/v2 v2.4.0/go.mod h1:OLaKh+giepO8j7teevrNwiy/fwf8LXgoc9g7rwaE1jk= github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible h1:1G1pk05UrOh0NlF1oeaaix1x8XzrfjIDK47TY0Zehcw= github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0rYXWg0= @@ -66,6 +70,8 @@ github.com/bodgit/sevenzip v1.6.0 h1:a4R0Wu6/P1o1pP/3VV++aEOcyeBxeO/xE2Y9NSTrr6A github.com/bodgit/sevenzip v1.6.0/go.mod h1:zOBh9nJUof7tcrlqJFv1koWRrhz3LbDbUNngkuZxLMc= github.com/bodgit/windows v1.0.1 h1:tF7K6KOluPYygXa3Z2594zxlkbKPAOvqr97etrGNIz4= github.com/bodgit/windows v1.0.1/go.mod h1:a6JLwrB4KrTR5hBpp8FI9/9W9jJfeQ2h4XDXU74ZCdM= +github.com/brianvoe/gofakeit/v7 v7.2.1 h1:AGojgaaCdgq4Adzrd2uWdbGNDyX6MWNhHdQBraNfOHI= +github.com/brianvoe/gofakeit/v7 v7.2.1/go.mod h1:QXuPeBw164PJCzCUZVmgpgHJ3Llj49jSLVkKPMtxtxA= github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/charmbracelet/glamour v0.8.0 h1:tPrjL3aRcQbn++7t18wOpgLyl8wrOHUEDS7IZ68QtZs= @@ -93,8 +99,8 @@ github.com/cloudflare/cfssl v1.6.4/go.mod h1:8b3CQMxfWPAeom3zBnGJ6sd+G1NkL5TXqmD github.com/cloudflare/circl v1.1.0/go.mod h1:prBCrKB9DV4poKZY1l9zBXg2QJY7mvgRvtMxxK7fi4I= github.com/cloudflare/circl v1.6.1 h1:zqIqSPIndyBh1bjLVVDHMPpVKqp8Su/V+6MeDzzQBQ0= github.com/cloudflare/circl v1.6.1/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs= -github.com/cnf/structhash v0.0.0-20201127153200-e1b16c1ebc08 h1:ox2F0PSMlrAAiAdknSRMDrAr8mfxPCfSZolH+/qQnyQ= -github.com/cnf/structhash v0.0.0-20201127153200-e1b16c1ebc08/go.mod h1:pCxVEbcm3AMg7ejXyorUXi6HQCzOIBf7zEDVPtw0/U4= +github.com/cnf/structhash v0.0.0-20250313080605-df4c6cc74a9a h1:Ohw57yVY2dBTt+gsC6aZdteyxwlxfbtgkFEMTEkwgSw= +github.com/cnf/structhash v0.0.0-20250313080605-df4c6cc74a9a/go.mod h1:pCxVEbcm3AMg7ejXyorUXi6HQCzOIBf7zEDVPtw0/U4= github.com/corona10/goimagehash v1.1.0 h1:teNMX/1e+Wn/AYSbLHX8mj+mF9r60R1kBeqE9MkoYwI= github.com/corona10/goimagehash v1.1.0/go.mod h1:VkvE0mLn84L4aF8vCb6mafVajEb6QYMHl2ZJLn0mOGI= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -121,10 +127,10 @@ github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHqu github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= -github.com/gaissmai/bart v0.20.5 h1:ehoWZWQ7j//qt0K0Zs4i9hpoPpbgqsMQiR8W2QPJh+c= -github.com/gaissmai/bart v0.20.5/go.mod h1:cEed+ge8dalcbpi8wtS9x9m2hn/fNJH5suhdGQOHnYk= -github.com/go-faker/faker/v4 v4.6.1 h1:xUyVpAjEtB04l6XFY0V/29oR332rOSPWV4lU8RwDt4k= -github.com/go-faker/faker/v4 v4.6.1/go.mod h1:arSdxNCSt7mOhdk8tEolvHeIJ7eX4OX80wXjKKvkKBY= +github.com/gaissmai/bart v0.26.0 h1:xOZ57E9hJLBiQaSyeZa9wgWhGuzfGACgqp4BE77OkO0= +github.com/gaissmai/bart v0.26.0/go.mod h1:GREWQfTLRWz/c5FTOsIw+KkscuFkIV5t8Rp7Nd1Td5c= +github.com/go-faker/faker/v4 v4.7.0 h1:VboC02cXHl/NuQh5lM2W8b87yp4iFXIu59x4w0RZi4E= +github.com/go-faker/faker/v4 v4.7.0/go.mod h1:u1dIRP5neLB6kTzgyVjdBOV5R1uP7BdxkcWk7tiKQXk= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= @@ -194,6 +200,10 @@ github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+ github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/gorilla/css v1.0.1 h1:ntNaBIghp6JmvWnxbZKANoLyuXTPZ4cAMlo6RyhlbO8= github.com/gorilla/css v1.0.1/go.mod h1:BvnYkspnSzMmwRK+b8/xgNPLiIuNZr6vbZBTPQ2A3b0= +github.com/gosimple/slug v1.15.0 h1:wRZHsRrRcs6b0XnxMUBM6WK1U1Vg5B0R7VkIf1Xzobo= +github.com/gosimple/slug v1.15.0/go.mod h1:UiRaFH+GEilHstLUmcBgWcI42viBN7mAb818JrYOeFQ= +github.com/gosimple/unidecode v1.0.1 h1:hZzFTMMqSswvf0LBJZCZgThIZrpDHFXux9KeGmn6T/o= +github.com/gosimple/unidecode v1.0.1/go.mod h1:CP0Cr1Y1kogOtx0bJblKzsVWrqYaqfNOnHzpgWw4Awc= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -212,10 +222,10 @@ github.com/hdm/jarm-go v0.0.7/go.mod h1:kinGoS0+Sdn1Rr54OtanET5E5n7AlD6T6CrJAKDj github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/iangcarroll/cookiemonster v1.6.0 h1:NPFkn/ZZYZgzXhJ1awRnYhZ3fJK3hKWgbctfTW21kew= +github.com/iangcarroll/cookiemonster v1.6.0/go.mod h1:n3MvoAq56NkNyCEyhcYs3ZJMzTc9rL3w7IaITI0apMg= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20230524184225-eabc099b10ab/go.mod h1:gx7rwoVhcfuVKG5uya9Hs3Sxj7EIvldVofAWIUtGouw= -github.com/jaytaylor/html2text v0.0.0-20230321000545-74c2419ad056 h1:iCHtR9CQyktQ5+f3dMVZfwD2KWJUgm7M0gdL9NGr8KA= -github.com/jaytaylor/html2text v0.0.0-20230321000545-74c2419ad056/go.mod h1:CVKlgaMiht+LXvHG173ujK6JUhZXKb2u/BQtjPDIvyk= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= @@ -254,7 +264,6 @@ github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHP github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= @@ -265,8 +274,8 @@ github.com/mholt/archives v0.1.0/go.mod h1:j/Ire/jm42GN7h90F5kzj6hf6ZFzEH66de+hm github.com/microcosm-cc/bluemonday v1.0.27 h1:MpEUotklkwCSLeH+Qdx1VJgNqLlpY2KXwXFM08ygZfk= github.com/microcosm-cc/bluemonday v1.0.27/go.mod h1:jFi9vgW+H7c3V0lb6nR74Ib/DIB5OBs92Dimizgw2cA= github.com/miekg/dns v1.1.35/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= -github.com/miekg/dns v1.1.62 h1:cN8OuEF1/x5Rq6Np+h1epln8OiyPWV+lROx9LxcGgIQ= -github.com/miekg/dns v1.1.62/go.mod h1:mvDlcItzm+br7MToIKqkglaGhlFMHJ9DTNNWONWXbNQ= +github.com/miekg/dns v1.1.68 h1:jsSRkNozw7G/mnmXULynzMNIsgY2dHC8LO6U6Ij2JEA= +github.com/miekg/dns v1.1.68/go.mod h1:fujopn7TB3Pu3JM69XaawiU0wqjpL9/8xGop5UrTPps= github.com/minio/selfupdate v0.6.1-0.20230907112617-f11e74f84ca7 h1:yRZGarbxsRytL6EGgbqK2mCY+Lk5MWKQYKJT2gEglhc= github.com/minio/selfupdate v0.6.1-0.20230907112617-f11e74f84ca7/go.mod h1:bO02GTIPCMQFTEvE5h4DjYB58bCoZ35XLeBf0buTDdM= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -278,16 +287,14 @@ github.com/mreiferson/go-httpclient v0.0.0-20160630210159-31f0106b4474/go.mod h1 github.com/mreiferson/go-httpclient v0.0.0-20201222173833-5e475fde3a4d/go.mod h1:OQA4XLvDbMgS8P0CevmM4m9Q3Jq4phKUzcocxuGJ5m8= github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s= github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8= -github.com/muesli/termenv v0.15.3-0.20240618155329-98d742f6907a h1:2MaM6YC3mGu54x+RKAA6JiFFHlHDY1UbkxqppT7wYOg= -github.com/muesli/termenv v0.15.3-0.20240618155329-98d742f6907a/go.mod h1:hxSnBBYLK21Vtq/PHd0S2FYCxBXzBua8ov5s1RobyRQ= +github.com/muesli/termenv v0.16.0 h1:S5AlUN9dENB57rsbnkPyfdGuWIlkmzJjbFf0Tf5FWUc= +github.com/muesli/termenv v0.16.0/go.mod h1:ZRfOIKPFDYQoDFF4Olj7/QJbW60Ol/kL1pU3VfY/Cnk= github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ= github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8= -github.com/nwaples/rardecode/v2 v2.0.0-beta.4.0.20241112120701-034e449c6e78 h1:MYzLheyVx1tJVDqfu3YnN4jtnyALNzLvwl+f58TcvQY= -github.com/nwaples/rardecode/v2 v2.0.0-beta.4.0.20241112120701-034e449c6e78/go.mod h1:yntwv/HfMc/Hbvtq9I19D1n58te3h6KsqCf3GxyfBGY= +github.com/nwaples/rardecode/v2 v2.2.0 h1:4ufPGHiNe1rYJxYfehALLjup4Ls3ck42CWwjKiOqu0A= +github.com/nwaples/rardecode/v2 v2.2.0/go.mod h1:7uz379lSxPe6j9nvzxUZ+n7mnJNgjsRNb6IbvGVHRmw= github.com/nxadm/tail v1.4.11 h1:8feyoE3OzPrcshW5/MJ4sGESc5cqmGkGCWlco4l0bqY= github.com/nxadm/tail v1.4.11/go.mod h1:OTaG3NK980DZzxbRq6lEuzgU+mug70nY11sMd4JXXHc= -github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= -github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= @@ -310,14 +317,14 @@ github.com/projectdiscovery/asnmap v1.1.1 h1:ImJiKIaACOT7HPx4Pabb5dksolzaFYsD1kI github.com/projectdiscovery/asnmap v1.1.1/go.mod h1:QT7jt9nQanj+Ucjr9BqGr1Q2veCCKSAVyUzLXfEcQ60= github.com/projectdiscovery/blackrock v0.0.1 h1:lHQqhaaEFjgf5WkuItbpeCZv2DUIE45k0VbGJyft6LQ= github.com/projectdiscovery/blackrock v0.0.1/go.mod h1:ANUtjDfaVrqB453bzToU+YB4cUbvBRpLvEwoWIwlTss= -github.com/projectdiscovery/cdncheck v1.1.28 h1:Nn+9SuB4Xv56lFn5zN5hWB0Kq/5veAUX0xnRb+K+IeM= -github.com/projectdiscovery/cdncheck v1.1.28/go.mod h1:dFEGsG0qAJY0AaRr2N1BY0OtZiTxS4kYeT5+OkF8t1U= +github.com/projectdiscovery/cdncheck v1.2.9 h1:DsT+uZdGduJSsSrTbFRl1JDcsDHrPKi0v+/KziQnuTw= +github.com/projectdiscovery/cdncheck v1.2.9/go.mod h1:ibL9HoZs2JYTEUBOZo4f+W+XEzQifFLOf4bpgFStgj4= github.com/projectdiscovery/clistats v0.1.1 h1:8mwbdbwTU4aT88TJvwIzTpiNeow3XnAB72JIg66c8wE= github.com/projectdiscovery/clistats v0.1.1/go.mod h1:4LtTC9Oy//RiuT1+76MfTg8Hqs7FQp1JIGBM3nHK6a0= -github.com/projectdiscovery/dsl v0.5.0 h1:3HHY14FNmdwWXq3pi9dd8JjUHQzskZjLD/pZKVx5Vi4= -github.com/projectdiscovery/dsl v0.5.0/go.mod h1:Fr+zIQJfMNy+RTj5KFgozfvDaiQQEKMyrKXl75aGgxY= -github.com/projectdiscovery/fastdialer v0.4.2 h1:uB+p8CinbrzlAwfGeTyHKShjnYBj60rcZ8FoBtGlg7I= -github.com/projectdiscovery/fastdialer v0.4.2/go.mod h1:g3ikfujsn3g+ZdyypNpMzMTj2qHHXXqjZL9YioX53Ok= +github.com/projectdiscovery/dsl v0.8.4 h1:p3rvzJae9BecOMufdYex3DX9zZeQNaXwVQe4kCEAOtE= +github.com/projectdiscovery/dsl v0.8.4/go.mod h1:msE7dGAuHYRrKddEwB1yoQ5dHrzzyimQUjsGDsMDis8= +github.com/projectdiscovery/fastdialer v0.4.15 h1:AHDgyydTdE5uUHGwzpvIDslY2AQn1kVq79gKEgFGAbE= +github.com/projectdiscovery/fastdialer v0.4.15/go.mod h1:X0l4+KqOE/aIL00pyTnBj4pWQDPYnCGL7cwZsJu6SCQ= github.com/projectdiscovery/fdmax v0.0.4 h1:K9tIl5MUZrEMzjvwn/G4drsHms2aufTn1xUdeVcmhmc= github.com/projectdiscovery/fdmax v0.0.4/go.mod h1:oZLqbhMuJ5FmcoaalOm31B1P4Vka/CqP50nWjgtSz+I= github.com/projectdiscovery/freeport v0.0.7 h1:Q6uXo/j8SaV/GlAHkEYQi8WQoPXyJWxyspx+aFmz9Qk= @@ -326,36 +333,36 @@ github.com/projectdiscovery/goconfig v0.0.1 h1:36m3QjohZvemqh9bkJAakaHsm9iEZ2AcQ github.com/projectdiscovery/goconfig v0.0.1/go.mod h1:CPO25zR+mzTtyBrsygqsHse0sp/4vB/PjaHi9upXlDw= github.com/projectdiscovery/goflags v0.1.74 h1:n85uTRj5qMosm0PFBfsvOL24I7TdWRcWq/1GynhXS7c= github.com/projectdiscovery/goflags v0.1.74/go.mod h1:UMc9/7dFz2oln+10tv6cy+7WZKTHf9UGhaNkF95emh4= -github.com/projectdiscovery/gologger v1.1.54 h1:WMzvJ8j/4gGfPKpCttSTaYCVDU1MWQSJnk3wU8/U6Ws= -github.com/projectdiscovery/gologger v1.1.54/go.mod h1:vza/8pe2OKOt+ujFWncngknad1XWr8EnLKlbcejOyUE= +github.com/projectdiscovery/gologger v1.1.59 h1:3XFidZHrUqtvL1CUbw7L1jtwiUmTZxT2CoQ0I/yiNh4= +github.com/projectdiscovery/gologger v1.1.59/go.mod h1:8FJFKmo0N4ITIH3n1Jy4ze6ijr+mA3t78g+VpN8uBRU= 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/hmap v0.0.91 h1:8vSTU+3hmMfA5Qd14ceq4j7wnUVUJcXdqQgqbsFBea0= -github.com/projectdiscovery/hmap v0.0.91/go.mod h1:BxEg8WXqxqaOADPZ+xp2X6BY+znfV8dusCSGSFnsU3c= +github.com/projectdiscovery/hmap v0.0.95 h1:OO6MCySlK2xMzvJmsYUwdaI7YWv/U437OtsN0Ovw72k= +github.com/projectdiscovery/hmap v0.0.95/go.mod h1:KiTRdGd/GzX7uaoFWPrPBxPf4X/uZ9HTQ9dQ8x7x1bo= github.com/projectdiscovery/machineid v0.0.0-20240226150047-2e2c51e35983 h1:ZScLodGSezQVwsQDtBSMFp72WDq0nNN+KE/5DHKY5QE= github.com/projectdiscovery/machineid v0.0.0-20240226150047-2e2c51e35983/go.mod h1:3G3BRKui7nMuDFAZKR/M2hiOLtaOmyukT20g88qRQjI= -github.com/projectdiscovery/mapcidr v1.1.34 h1:udr83vQ7oz3kEOwlsU6NC6o08leJzSDQtls1wmXN/kM= -github.com/projectdiscovery/mapcidr v1.1.34/go.mod h1:1+1R6OkKSAKtWDXE9RvxXtXPoajXTYX0eiEdkqlhQqQ= -github.com/projectdiscovery/networkpolicy v0.1.18 h1:DAeP73SvcuT4evaohNS7BPELw+VtvcVt4PaTK3fC1qA= -github.com/projectdiscovery/networkpolicy v0.1.18/go.mod h1:2yWanKsU2oBZ75ch94IsEQy6hByFp+3oTiSyC6ew3TE= -github.com/projectdiscovery/ratelimit v0.0.81 h1:u6lW+rAhS/UO0amHTYmYLipPK8NEotA9521hdojBtgI= -github.com/projectdiscovery/ratelimit v0.0.81/go.mod h1:tK04WXHuC4i6AsFkByInODSNf45gd9sfaMHzmy2bAsA= +github.com/projectdiscovery/mapcidr v1.1.97 h1:7FkxNNVXp+m1rIu5Nv/2SrF9k4+LwP8QuWs2puwy+2w= +github.com/projectdiscovery/mapcidr v1.1.97/go.mod h1:9dgTJh1SP02gYZdpzMjm6vtYFkEHQHoTyaVNvaeJ7lA= +github.com/projectdiscovery/networkpolicy v0.1.27 h1:GsbvDIW3nPstAx8Beke6rtn95PhXnOcoXrnjcohn5Xk= +github.com/projectdiscovery/networkpolicy v0.1.27/go.mod h1:/3XfgnxKNuxaTZc6wZ/Pq6fiKvK8N4OQyLmfcUeDk2E= +github.com/projectdiscovery/ratelimit v0.0.82 h1:rtO5SQf5uQFu5zTahTaTcO06OxmG8EIF1qhdFPIyTak= +github.com/projectdiscovery/ratelimit v0.0.82/go.mod h1:z076BrLkBb5yS7uhHNoCTf8X/BvFSGRxwQ8EzEL9afM= github.com/projectdiscovery/rawhttp v0.1.90 h1:LOSZ6PUH08tnKmWsIwvwv1Z/4zkiYKYOSZ6n+8RFKtw= github.com/projectdiscovery/rawhttp v0.1.90/go.mod h1:VZYAM25UI/wVB3URZ95ZaftgOnsbphxyAw/XnQRRz4Y= -github.com/projectdiscovery/retryabledns v1.0.103 h1:rPnoMTK+CXLbO8kT7ODtwbhyQGAUpJsqhVq8AAvu1bs= -github.com/projectdiscovery/retryabledns v1.0.103/go.mod h1:sfu91YrZkb8Ccvij8YDTV96cQt69IPqnfa+OEFUke1o= -github.com/projectdiscovery/retryablehttp-go v1.0.118 h1:ylbb2mKOfFQOwbtGyI1C0yzudl/UvJvC9YbWIPMyXQY= -github.com/projectdiscovery/retryablehttp-go v1.0.118/go.mod h1:pAQWFh6lg9Gmno5zrQxbfuAbc9OvIugl5P9kaoXztgM= +github.com/projectdiscovery/retryabledns v1.0.108 h1:47LYRW2LY/0cDnZQfUhoOHNxe9rNc9NQ9ZfNrV/GbyM= +github.com/projectdiscovery/retryabledns v1.0.108/go.mod h1:j7H7K6JZePh9PeNleeRUtDSrkUKMpwDhZw3Ogewzio8= +github.com/projectdiscovery/retryablehttp-go v1.0.131 h1:OU2x9fVDIWnDoKvT8tKbaCONTL1gHnTOIFQFXmnEOE0= +github.com/projectdiscovery/retryablehttp-go v1.0.131/go.mod h1:ttW+Zka1L8IwEUhJ4zArbC+pKZum7b47fzV+4VGN6cA= 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.2.0 h1:n92B+ZAIzWW3+UFOJpI4ILWZuDcQHHLwVqbWXnZPJdc= -github.com/projectdiscovery/tlsx v1.2.0/go.mod h1:ddPZIluCZBN4N0nn+H0f/QjimF7MOhpQ5RXkJ7zZnwA= -github.com/projectdiscovery/useragent v0.0.101 h1:8A+XOJ/nIH+WqW8ogLxJ/psemGp8ATQ2/GuKroJ/81E= -github.com/projectdiscovery/useragent v0.0.101/go.mod h1:RGoRw1BQ/lJnhYMbMpEKjyAAgCaDCr/+GsULo5yEJ2I= -github.com/projectdiscovery/utils v0.4.22 h1:OO3FU2uX967sQxu5JtpdBZNzOevvKHAhWqkoTGl+C0A= -github.com/projectdiscovery/utils v0.4.22/go.mod h1:3l84gpCwL9KG1/ZmslOBABCrk84CcpGWJZfR8wZysR4= -github.com/projectdiscovery/wappalyzergo v0.2.38 h1:R7gf5NlndtKd2OFT34uIgFlXDJzE8MXRIwQandAC40M= -github.com/projectdiscovery/wappalyzergo v0.2.38/go.mod h1:XQSgnMQnxliVw2wjKehxeJ4QTRluOJpmm55gLHdztVQ= +github.com/projectdiscovery/tlsx v1.2.1 h1:R8QgKb/vxd6Y0cfGFBYs4nn0zodHABeeLPqJjs2mNrA= +github.com/projectdiscovery/tlsx v1.2.1/go.mod h1:p19UHGQ6bvcbvhO4NvYBKOxlE4QvrUaectx9g/Mm3JA= +github.com/projectdiscovery/useragent v0.0.102 h1:Xfr8a7LQhIu0zeSz5gBxGCdyuqZbhkOMAEQUcEZXyBU= +github.com/projectdiscovery/useragent v0.0.102/go.mod h1:DIfLRBKZ6dLhHRnMYkxdg6Jpu0kpE3pJlMG94dsIchY= +github.com/projectdiscovery/utils v0.6.1-0.20251030144701-ce5c4b44e1e6 h1:nvszzYNHYnc8X+Dm68zMuYNNesZJp7QWfe8EEyL4azc= +github.com/projectdiscovery/utils v0.6.1-0.20251030144701-ce5c4b44e1e6/go.mod h1:GOjhpPLmpMHcYJKI0vhjvjdczMQf3jWdUgYiBeKkwVk= +github.com/projectdiscovery/wappalyzergo v0.2.54 h1:8w0qUb0dO9N5FN1y4M8pIzDNqLCj0MrITqV/1xp05Lw= +github.com/projectdiscovery/wappalyzergo v0.2.54/go.mod h1:lwuDLdAqWDZ1IL8OQnoNQ0t17UP9AQSvVuFcDAm4FpQ= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/refraction-networking/utls v1.7.1 h1:dxg+jla3uocgN8HtX+ccwDr68uCBBO3qLrkZUbqkcw0= github.com/refraction-networking/utls v1.7.1/go.mod h1:TUhh27RHMGtQvjQq+RyO11P6ZNQNBb3N0v7wsEjKAIQ= @@ -373,6 +380,10 @@ github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d h1:hrujxIzL1woJ7 github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d/go.mod h1:uugorj2VCxiV1x+LzaIdVa9b4S4qGAcH6cbhh4qVxOU= github.com/sashabaranov/go-openai v1.37.0 h1:hQQowgYm4OXJ1Z/wTrE+XZaO20BYsL0R3uRPSpfNZkY= github.com/sashabaranov/go-openai v1.37.0/go.mod h1:lj5b/K+zjTSFxVLijLSTDZuP7adOgerWeFyZLUhAKRg= +github.com/sebdah/goldie/v2 v2.7.1 h1:PkBHymaYdtvEkZV7TmyqKxdmn5/Vcj+8TpATWZjnG5E= +github.com/sebdah/goldie/v2 v2.7.1/go.mod h1:oZ9fp0+se1eapSRjfYbsV/0Hqhbuu3bJVvKI/NNtssI= +github.com/sergi/go-diff v1.4.0 h1:n/SP9D5ad1fORl+llWyN+D6qoUETXNZARKjyY2/KVCw= +github.com/sergi/go-diff v1.4.0/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4= github.com/shirou/gopsutil/v3 v3.24.2 h1:kcR0erMbLg5/3LcInpw0X/rrPSqq4CDPyI6A6ZRC18Y= github.com/shirou/gopsutil/v3 v3.24.2/go.mod h1:tSg/594BcA+8UdQU2XcW803GWYgdtauFFPgJCJKZlVk= github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM= @@ -386,8 +397,6 @@ github.com/sorairolake/lzip-go v0.3.5 h1:ms5Xri9o1JBIWvOFAorYtUNik6HI3HgBTkISiqu github.com/sorairolake/lzip-go v0.3.5/go.mod h1:N0KYq5iWrMXI0ZEXKXaS9hCyOjZUQdBDEIbXfoUwbdk= github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf h1:pvbZ0lM0XWPBqUKqFU8cmavspvIl9nulOYwdy6IFRRo= -github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf/go.mod h1:RJID2RhlZKId02nZ62WenDCkgHFerpIOmW0iT7GKmXM= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= @@ -400,8 +409,8 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= -github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE= github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= github.com/therootcompany/xz v1.0.1 h1:CmOtsn1CbtmyYiusbfmhmkpAAETj0wBIH6kCYaX+xzw= @@ -419,8 +428,9 @@ github.com/tidwall/grect v0.1.4 h1:dA3oIgNgWdSspFzn1kS4S/RDpZFLrIxAZOdJKjYapOg= github.com/tidwall/grect v0.1.4/go.mod h1:9FBsaYRaR0Tcy4UwefBX/UDcDcDy9V5jUcxHzv2jd5Q= github.com/tidwall/lotsa v1.0.2 h1:dNVBH5MErdaQ/xd9s769R31/n2dXavsQ0Yf4TMEHHw8= github.com/tidwall/lotsa v1.0.2/go.mod h1:X6NiU+4yHA3fE3Puvpnn1XMDrFZrE9JO2/w+UMuqgR8= -github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/match v1.2.0 h1:0pt8FlkOwjN2fPt4bIl4BoNxb98gGHN2ObFEDkrfZnM= +github.com/tidwall/match v1.2.0/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4= github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= @@ -433,12 +443,14 @@ github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0h github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk= github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY= github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= -github.com/ulikunitz/xz v0.5.12 h1:37Nm15o69RwBkXM0J6A5OlE67RZTfzUxTj8fB3dfcsc= -github.com/ulikunitz/xz v0.5.12/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= +github.com/ulikunitz/xz v0.5.15 h1:9DNdB5s+SgV3bQ2ApL10xRc35ck0DuIX/isZvIk+ubY= +github.com/ulikunitz/xz v0.5.15/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= github.com/weppos/publicsuffix-go v0.13.0/go.mod h1:z3LCPQ38eedDQSwmsSRW4Y7t2L8Ln16JPQ02lHAdn5k= github.com/weppos/publicsuffix-go v0.30.2/go.mod h1:/hGscit36Yt+wammfBBwdMdxBT8btsTt6KvwO9OvMyM= -github.com/weppos/publicsuffix-go v0.40.3-0.20250408071509-6074bbe7fd39 h1:Bz/zVM/LoGZ9IztGBHrq2zlFQQbEG8dBYnxb4hamIHM= -github.com/weppos/publicsuffix-go v0.40.3-0.20250408071509-6074bbe7fd39/go.mod h1:2oFzEwGYI7lhiqG0YkkcKa6VcpjVinQbWxaPzytDmLA= +github.com/weppos/publicsuffix-go v0.50.0 h1:M178k6l8cnh9T1c1cStkhytVxdk5zPd6gGZf8ySIuVo= +github.com/weppos/publicsuffix-go v0.50.0/go.mod h1:VXhClBYMlDrUsome4pOTpe68Ui0p6iQRAbyHQD1yKoU= +github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c= +github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU= github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E= github.com/yl2chen/cidranger v1.0.2 h1:lbOWZVCG1tCRX4u24kuM1Tb4nHqWkDxwLdoS+SevawU= @@ -459,8 +471,8 @@ github.com/ysmood/leakless v0.9.0 h1:qxCG5VirSBvmi3uynXFkcnLMzkphdh3xx5FtrORwDCU github.com/ysmood/leakless v0.9.0/go.mod h1:R8iAXPRaG97QJwqxs74RdwzcRHT1SWCGTNqY8q0JvMQ= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yuin/goldmark v1.7.1/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= -github.com/yuin/goldmark v1.7.4 h1:BDXOHExt+A7gwPCJgPIIq7ENvceR7we7rOS9TNoLZeg= -github.com/yuin/goldmark v1.7.4/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= +github.com/yuin/goldmark v1.7.13 h1:GPddIs617DnBLFFVJFgpo1aBfe/4xcvMc3SB5t/D0pA= +github.com/yuin/goldmark v1.7.13/go.mod h1:ip/1k0VRfGynBgxOz0yCqHrbZXhcjxyuS66Brc7iBKg= github.com/yuin/goldmark-emoji v1.0.3 h1:aLRkLHOuBR2czCY4R8olwMjID+tENfhyFDMCRhbIQY4= github.com/yuin/goldmark-emoji v1.0.3/go.mod h1:tTkZEbwu5wkPmgTcitqddVxY9osFZiavD+r4AzQrh1U= github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= @@ -505,8 +517,8 @@ golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= -golang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM= -golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY= +golang.org/x/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04= +golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -515,8 +527,8 @@ golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= -golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8 h1:yqrTHse8TCMW1M1ZCP+VAR/l0kKxwaAIqN/il7x4voA= -golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8/go.mod h1:tujkw807nyEEAamNbDrEGzRav+ilXA7PCRAd6xsmwiU= +golang.org/x/exp v0.0.0-20250911091902-df9299821621 h1:2id6c1/gto0kaHYyrixvknJ8tUK/Qs5IsmBtrc+FtgU= +golang.org/x/exp v0.0.0-20250911091902-df9299821621/go.mod h1:TwQYMMnGpvZyc+JpB/UAuTNIsVJifOlSkrZkhcvpVUk= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -539,8 +551,8 @@ golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/mod v0.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w= -golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= +golang.org/x/mod v0.28.0 h1:gQBtGhjxykdjY9YhZpSlZIsbnaE2+PgjfLWUQTnoZ1U= +golang.org/x/mod v0.28.0/go.mod h1:yfB/L0NOf/kmEbXjzCPOx1iK1fRutOydrCMsqRhEBxI= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -571,8 +583,8 @@ golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= -golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs= -golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8= +golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4= +golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -594,8 +606,8 @@ golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw= -golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug= +golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -636,8 +648,8 @@ golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA= -golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ= +golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= @@ -650,8 +662,8 @@ golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= -golang.org/x/term v0.33.0 h1:NuFncQrRcaRvVmgRkvM3j/F00gWIAlcmlB8ACEKmGIg= -golang.org/x/term v0.33.0/go.mod h1:s18+ql9tYWp1IfpV9DmCtQDDSRBUjKaw9M1eAv5UeF0= +golang.org/x/term v0.36.0 h1:zMPR+aF8gfksFprF/Nc/rd1wRS1EI6nDBGyWAvDzx2Q= +golang.org/x/term v0.36.0/go.mod h1:Qu394IJq6V6dCBRgwqshf3mPF85AqzYEzofzRdZkWss= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -667,8 +679,8 @@ golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= -golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4= -golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU= +golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k= +golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0= @@ -702,8 +714,8 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= -golang.org/x/tools v0.34.0 h1:qIpSLOxeCYGg9TrcJokLBG4KFA6d795g0xkBkiESGlo= -golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg= +golang.org/x/tools v0.37.0 h1:DVSRzp7FwePZW356yEAChSdNcQo6Nsp+fex1SUW09lE= +golang.org/x/tools v0.37.0/go.mod h1:MBN5QPQtLMHVdvsbtarmTNukZDdgwdwlO5qGacAzF0w= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/internal/pdcp/writer.go b/internal/pdcp/writer.go index 61327eeb5..fbad91abd 100644 --- a/internal/pdcp/writer.go +++ b/internal/pdcp/writer.go @@ -18,7 +18,7 @@ import ( pdcpauth "github.com/projectdiscovery/utils/auth/pdcp" "github.com/projectdiscovery/utils/conversion" "github.com/projectdiscovery/utils/env" - errorutil "github.com/projectdiscovery/utils/errors" + "github.com/projectdiscovery/utils/errkit" // unitutils "github.com/projectdiscovery/utils/unit" updateutils "github.com/projectdiscovery/utils/update" urlutil "github.com/projectdiscovery/utils/url" @@ -71,7 +71,7 @@ func NewUploadWriterCallback(ctx context.Context, creds *pdcpauth.PDCPCredential var err error tmp, err := urlutil.Parse(creds.Server) if err != nil { - return nil, errorutil.NewWithErr(err).Msgf("could not parse server url") + return nil, errkit.Wrap(err, "could not parse server url") } tmp.Path = uploadEndpoint tmp.Update() @@ -99,12 +99,11 @@ func (u *UploadWriter) GetWriterCallback() runner.OnResultCallback { } // SetAssetID sets the scan id for the upload writer -func (u *UploadWriter) SetAssetID(id string) error { +func (u *UploadWriter) SetAssetID(id string) { if !xidRegex.MatchString(id) { - return fmt.Errorf("invalid asset id provided") + gologger.Warning().Msgf("invalid asset id provided (unknown xid format): %s", id) } u.assetGroupID = id - return nil } // SetAssetGroupName sets the scan name for the upload writer @@ -186,7 +185,7 @@ func (u *UploadWriter) autoCommit(ctx context.Context) { // uploadChunk uploads a chunk of data to the server func (u *UploadWriter) uploadChunk(buff *bytes.Buffer) error { if err := u.upload(buff.Bytes()); err != nil { - return errorutil.NewWithErr(err).Msgf("could not upload chunk") + return errkit.Wrap(err, "could not upload chunk") } // if successful, reset the buffer buff.Reset() @@ -198,23 +197,25 @@ func (u *UploadWriter) uploadChunk(buff *bytes.Buffer) error { func (u *UploadWriter) upload(data []byte) error { req, err := u.getRequest(data) if err != nil { - return errorutil.NewWithErr(err).Msgf("could not create upload request") + return errkit.Wrap(err, "could not create upload request") } resp, err := u.client.Do(req) if err != nil { - return errorutil.NewWithErr(err).Msgf("could not upload results") + return errkit.Wrap(err, "could not upload results") } - defer resp.Body.Close() + defer func() { + _ = resp.Body.Close() + }() bin, err := io.ReadAll(resp.Body) if err != nil { - return errorutil.NewWithErr(err).Msgf("could not get id from response") + return errkit.Wrap(err, "could not get id from response") } if resp.StatusCode != http.StatusOK { return fmt.Errorf("could not upload results got status code %v on %v", resp.StatusCode, resp.Request.URL.String()) } var uploadResp uploadResponse if err := json.Unmarshal(bin, &uploadResp); err != nil { - return errorutil.NewWithErr(err).Msgf("could not unmarshal response got %v", string(bin)) + return errkit.Wrapf(err, "could not unmarshal response got %v", string(bin)) } if uploadResp.ID != "" && u.assetGroupID == "" { u.assetGroupID = uploadResp.ID @@ -239,15 +240,15 @@ func (u *UploadWriter) getRequest(bin []byte) (*retryablehttp.Request, error) { } req, err := retryablehttp.NewRequest(method, url, bytes.NewReader(bin)) if err != nil { - return nil, errorutil.NewWithErr(err).Msgf("could not create cloud upload request") + return nil, errkit.Wrap(err, "could not create cloud upload request") } // add pdtm meta params - req.URL.Params.Merge(updateutils.GetpdtmParams(runner.Version)) + req.Params.Merge(updateutils.GetpdtmParams(runner.Version)) // if it is upload endpoint also include name if it exists - if u.assetGroupName != "" && req.URL.Path == uploadEndpoint { - req.URL.Params.Add("name", u.assetGroupName) + if u.assetGroupName != "" && req.Path == uploadEndpoint { + req.Params.Add("name", u.assetGroupName) } - req.URL.Update() + req.Update() req.Header.Set(pdcpauth.ApiKeyHeaderName, u.creds.APIKey) if u.TeamID != "" { diff --git a/runner/banner.go b/runner/banner.go index 4da6637a6..fd6f56330 100644 --- a/runner/banner.go +++ b/runner/banner.go @@ -16,7 +16,7 @@ const banner = ` ` // Version is the current Version of httpx -const Version = `v1.7.1` +const Version = `v1.7.2` // showBanner is used to show the banner to the user func showBanner() { diff --git a/runner/headless.go b/runner/headless.go index 6c56b736e..f661639d9 100644 --- a/runner/headless.go +++ b/runner/headless.go @@ -12,9 +12,20 @@ import ( "github.com/go-rod/rod/lib/proto" "github.com/pkg/errors" fileutil "github.com/projectdiscovery/utils/file" + mapsutil "github.com/projectdiscovery/utils/maps" osutils "github.com/projectdiscovery/utils/os" + sliceutil "github.com/projectdiscovery/utils/slice" + stringsutil "github.com/projectdiscovery/utils/strings" ) +type NetworkRequest struct { + RequestID string + URL string + Method string + StatusCode int + ErrorType string +} + // MustDisableSandbox determines if the current os and user needs sandbox mode disabled func MustDisableSandbox() bool { // linux with root user needs "--no-sandbox" option @@ -99,11 +110,85 @@ func NewBrowser(proxy string, useLocal bool, optionalArgs map[string]string) (*B return engine, nil } -func (b *Browser) ScreenshotWithBody(url string, timeout time.Duration, idle time.Duration, headers []string, fullPage bool) ([]byte, string, error) { +func (b *Browser) ScreenshotWithBody(url string, timeout time.Duration, idle time.Duration, headers []string, fullPage bool, jsCodes []string) ([]byte, string, []NetworkRequest, error) { + page, networkRequests, err := b.setupPageAndNavigate(url, timeout, headers, jsCodes) + if err != nil { + return nil, "", []NetworkRequest{}, err + } + defer b.closePage(page) + + screenshot, body, err := b.takeScreenshotAndGetBody(page, idle, fullPage) + if err != nil { + return nil, "", networkRequests, err + } + + return screenshot, body, networkRequests, nil +} + +// setupPageAndNavigate opens a page, performs all adaptive actions including JS injection +func (b *Browser) setupPageAndNavigate(url string, timeout time.Duration, headers []string, jsCodes []string) (*rod.Page, []NetworkRequest, error) { page, err := b.engine.Page(proto.TargetCreateTarget{}) if err != nil { - return nil, "", err + return nil, []NetworkRequest{}, err } + + // Enable network + page.EnableDomain(proto.NetworkEnable{}) + + networkRequests := sliceutil.NewSyncSlice[NetworkRequest]() + requestsMap := mapsutil.NewSyncLockMap[string, *NetworkRequest]() + + // Intercept outbound requests + go page.EachEvent(func(e *proto.NetworkRequestWillBeSent) { + if !stringsutil.HasPrefixAnyI(e.Request.URL, "http://", "https://") { + return + } + req := &NetworkRequest{ + RequestID: string(e.RequestID), + URL: e.Request.URL, + Method: e.Request.Method, + StatusCode: -1, + ErrorType: "QUIT_BEFORE_RESOURCE_LOADING_END", + } + _ = requestsMap.Set(string(e.RequestID), req) + })() + // Intercept inbound responses + go page.EachEvent(func(e *proto.NetworkResponseReceived) { + if requestsMap.Has(string(e.RequestID)) { + req, _ := requestsMap.Get(string(e.RequestID)) + req.StatusCode = e.Response.Status + } + })() + // Intercept network end requests + go page.EachEvent(func(e *proto.NetworkLoadingFinished) { + if requestsMap.Has(string(e.RequestID)) { + req, _ := requestsMap.Get(string(e.RequestID)) + if req.StatusCode > 0 { + req.ErrorType = "" + } + networkRequests.Append(*req) + } + })() + // Intercept failed request + go page.EachEvent(func(e *proto.NetworkLoadingFailed) { + if requestsMap.Has(string(e.RequestID)) { + req, _ := requestsMap.Get(string(e.RequestID)) + req.StatusCode = 0 // mark to zero + req.ErrorType = getSimpleErrorType(e.ErrorText, string(e.Type), string(e.BlockedReason)) + if stringsutil.HasPrefixAnyI(req.URL, "http://", "https://") { + networkRequests.Append(*req) + } + } + })() + + // Handle any popup dialogs + go page.EachEvent(func(e *proto.PageJavascriptDialogOpening) { + _ = proto.PageHandleJavaScriptDialog{ + Accept: true, + PromptText: "", + }.Call(page) + })() + for _, header := range headers { headerParts := strings.SplitN(header, ":", 2) if len(headerParts) != 2 { @@ -115,14 +200,25 @@ func (b *Browser) ScreenshotWithBody(url string, timeout time.Duration, idle tim } page = page.Timeout(timeout) - defer page.Close() if err := page.Navigate(url); err != nil { - return nil, "", err + return page, networkRequests.Slice, err + } + + if len(jsCodes) > 0 { + _, err := b.ExecuteJavascriptCodesWithPage(page, jsCodes) + if err != nil { + return page, networkRequests.Slice, err + } } page.Timeout(5 * time.Second).WaitNavigation(proto.PageLifecycleEventNameFirstMeaningfulPaint)() + return page, networkRequests.Slice, nil +} + +// takeScreenshotAndGetBody performs the screenshot actions +func (b *Browser) takeScreenshotAndGetBody(page *rod.Page, idle time.Duration, fullPage bool) ([]byte, string, error) { if err := page.WaitLoad(); err != nil { return nil, "", err } @@ -141,8 +237,79 @@ func (b *Browser) ScreenshotWithBody(url string, timeout time.Duration, idle tim return screenshot, body, nil } +// closePage closes the page and performs cleanup +func (b *Browser) closePage(page *rod.Page) { + _ = page.Close() +} + func (b *Browser) Close() { - b.engine.Close() - os.RemoveAll(b.tempDir) + _ = b.engine.Close() + _ = os.RemoveAll(b.tempDir) // processutil.CloseProcesses(processutil.IsChromeProcess, b.pids) } +func getSimpleErrorType(errorText, errorType, blockedReason string) string { + switch blockedReason { + case "csp": + return "CSP_BLOCKED" + case "mixed-content": + return "MIXED_CONTENT" + case "origin": + return "CORS_BLOCKED" + case "subresource-filter": + return "AD_BLOCKED" + } + switch { + case strings.Contains(errorText, "net::ERR_NAME_NOT_RESOLVED"): + return "DNS_ERROR" + case strings.Contains(errorText, "net::ERR_CONNECTION_REFUSED"): + return "CONNECTION_REFUSED" + case strings.Contains(errorText, "net::ERR_CONNECTION_TIMED_OUT"): + return "TIMEOUT" + case strings.Contains(errorText, "net::ERR_CERT_"): + return "SSL_ERROR" + case strings.Contains(errorText, "net::ERR_BLOCKED_BY_CLIENT"): + return "CLIENT_BLOCKED" + case strings.Contains(errorText, "net::ERR_EMPTY_RESPONSE"): + return "EMPTY_RESPONSE" + } + switch errorType { + case "Failed": + return "NETWORK_FAILED" + case "Aborted": + return "ABORTED" + case "TimedOut": + return "TIMEOUT" + case "AccessDenied": + return "ACCESS_DENIED" + case "ConnectionClosed": + return "CONNECTION_CLOSED" + case "ConnectionReset": + return "CONNECTION_RESET" + case "ConnectionRefused": + return "CONNECTION_REFUSED" + case "NameNotResolved": + return "DNS_ERROR" + case "BlockedByClient": + return "CLIENT_BLOCKED" + } + // Fallback + if errorText != "" { + return "OTHER_ERROR" + } + return "UNKNOWN" +} + +func (b *Browser) ExecuteJavascriptCodesWithPage(page *rod.Page, jsc []string) ([]*proto.RuntimeRemoteObject, error) { + outputs := make([]*proto.RuntimeRemoteObject, 0, len(jsc)) + for _, js := range jsc { + if js == "" { + continue + } + output, err := page.Eval(js) + if err != nil { + return nil, err + } + outputs = append(outputs, output) + } + return outputs, nil +} diff --git a/runner/healthcheck.go b/runner/healthcheck.go index c48490fb1..ef79db7f0 100644 --- a/runner/healthcheck.go +++ b/runner/healthcheck.go @@ -43,7 +43,7 @@ func DoHealthCheck(options *Options, flagSet *goflags.FlagSet) string { test.WriteString(fmt.Sprintf("Config file \"%s\" Write => %s\n", cfgFilePath, testResult)) c4, err := net.Dial("tcp4", "scanme.sh:80") if err == nil && c4 != nil { - c4.Close() + _ = c4.Close() } testResult = "Ok" if err != nil { @@ -52,7 +52,7 @@ func DoHealthCheck(options *Options, flagSet *goflags.FlagSet) string { test.WriteString(fmt.Sprintf("IPv4 connectivity to scanme.sh:80 => %s\n", testResult)) c6, err := net.Dial("tcp6", "scanme.sh:80") if err == nil && c6 != nil { - c6.Close() + _ = c6.Close() } testResult = "Ok" if err != nil { diff --git a/runner/options.go b/runner/options.go index bbadb40be..0e41fd248 100644 --- a/runner/options.go +++ b/runner/options.go @@ -31,6 +31,7 @@ import ( fileutil "github.com/projectdiscovery/utils/file" sliceutil "github.com/projectdiscovery/utils/slice" stringsutil "github.com/projectdiscovery/utils/strings" + "github.com/projectdiscovery/utils/structs" updateutils "github.com/projectdiscovery/utils/update" wappalyzer "github.com/projectdiscovery/wappalyzergo" ) @@ -256,11 +257,13 @@ type Options struct { NoFallback bool NoFallbackScheme bool TechDetect bool + CustomFingerprintFile string TLSGrab bool protocol string ShowStatistics bool StatsInterval int RandomAgent bool + AutoReferer bool StoreChain bool StoreVisionReconClusters bool Deny customlist.CustomList @@ -310,6 +313,8 @@ type Options struct { OutputFilterCondition string OutputMatchCondition string StripFilter string + ListOutputFields bool + ExcludeOutputFields goflags.StringSlice //The OnResult callback function is invoked for each result. It is important to check for errors in the result before using Result.Err. OnResult OnResultCallback DisableUpdateCheck bool @@ -329,6 +334,9 @@ type Options struct { Protocol string OutputFilterErrorPagePath string DisableStdout bool + + JavascriptCodes goflags.StringSlice + // AssetUpload AssetUpload bool // AssetName @@ -379,8 +387,9 @@ func ParseOptions() *Options { flagSet.DynamicVarP(&options.ResponseBodyPreviewSize, "body-preview", "bp", 100, "display first N characters of response body"), flagSet.BoolVarP(&options.OutputServerHeader, "web-server", "server", false, "display server name"), flagSet.BoolVarP(&options.TechDetect, "tech-detect", "td", false, "display technology in use based on wappalyzer dataset"), + flagSet.StringVarP(&options.CustomFingerprintFile, "custom-fingerprint-file", "cff", "", "path to a custom fingerprint file for technology detection"), flagSet.BoolVar(&options.OutputMethod, "method", false, "display http request method"), - flagSet.BoolVar(&options.OutputWebSocket, "websocket", false, "display server using websocket"), + flagSet.BoolVarP(&options.OutputWebSocket, "websocket", "ws", false, "display server using websocket"), flagSet.BoolVar(&options.OutputIP, "ip", false, "display host ip"), flagSet.BoolVar(&options.OutputCName, "cname", false, "display host cname"), flagSet.BoolVarP(&options.ExtractFqdn, "efqdn", "extract-fqdn", false, "get domain and subdomains from response body and header in jsonl/csv output"), @@ -398,6 +407,7 @@ func ParseOptions() *Options { flagSet.BoolVar(&options.NoScreenshotFullPage, "no-screenshot-full-page", false, "disable saving full page screenshot"), flagSet.DurationVarP(&options.ScreenshotTimeout, "screenshot-timeout", "st", 10*time.Second, "set timeout for screenshot in seconds"), flagSet.DurationVarP(&options.ScreenshotIdle, "screenshot-idle", "sid", 1*time.Second, "set idle time before taking screenshot in seconds"), + flagSet.StringSliceVarP(&options.JavascriptCodes, "javascript-code", "jsc", nil, "execute JavaScript code after navigation", goflags.StringSliceOptions), ) flagSet.CreateGroup("matchers", "Matchers", @@ -432,6 +442,8 @@ func ParseOptions() *Options { flagSet.StringVarP(&options.OutputFilterResponseTime, "filter-response-time", "frt", "", "filter response with specified response time in seconds (-frt '> 1')"), flagSet.StringVarP(&options.OutputFilterCondition, "filter-condition", "fdc", "", "filter response with dsl expression condition"), flagSet.DynamicVar(&options.StripFilter, "strip", "html", "strips all tags in response. supported formats: html,xml"), + flagSet.BoolVarP(&options.ListOutputFields, "list-output-fields", "lof", false, "list of fields to output (comma separated)"), + flagSet.StringSliceVarP(&options.ExcludeOutputFields, "exclude-output-fields", "eof", nil, "exclude output fields output based on a condition", goflags.NormalizedOriginalStringSliceOptions), ) flagSet.CreateGroup("rate-limit", "Rate-Limit", @@ -473,7 +485,7 @@ func ParseOptions() *Options { flagSet.BoolVar(&options.ChainInStdout, "include-chain", false, "include redirect http chain in JSON output (-json only)"), flagSet.BoolVar(&options.StoreChain, "store-chain", false, "include http redirect chain in responses (-sr only)"), flagSet.BoolVarP(&options.StoreVisionReconClusters, "store-vision-recon-cluster", "svrc", false, "include visual recon clusters (-ss and -sr only)"), - flagSet.StringVarP(&options.Protocol, "protocol", "pr", "", "protocol to use (unknown, http11)"), + flagSet.StringVarP(&options.Protocol, "protocol", "pr", "", "protocol to use (unknown, http11, http2 [experimental], http3 [experimental])"), flagSet.StringVarP(&options.OutputFilterErrorPagePath, "filter-error-page-path", "fepp", "filtered_error_page.json", "path to store filtered error pages"), ) @@ -484,6 +496,7 @@ func ParseOptions() *Options { flagSet.Var(&options.Deny, "deny", "denied list of IP/CIDR's to process (file or comma separated)"), flagSet.StringVarP(&options.SniName, "sni-name", "sni", "", "custom TLS SNI name"), flagSet.BoolVar(&options.RandomAgent, "random-agent", true, "enable Random User-Agent to use"), + flagSet.BoolVar(&options.AutoReferer, "auto-referer", false, "set the Referer header to the current URL"), flagSet.VarP(&options.CustomHeaders, "header", "H", "custom http headers to send with request"), flagSet.StringVarP(&options.Proxy, "proxy", "http-proxy", "", "proxy (http|socks) to use (eg http://127.0.0.1:8080)"), flagSet.BoolVar(&options.Unsafe, "unsafe", false, "send raw requests skipping golang normalization"), @@ -544,6 +557,17 @@ func ParseOptions() *Options { _ = flagSet.Parse() + if options.ListOutputFields { + fields, err := structs.GetStructFields(Result{}) + if err != nil { + gologger.Fatal().Msgf("Could not get struct fields: %s\n", err) + } + for _, field := range fields { + fmt.Println(field) + } + os.Exit(0) + } + if options.OutputAll && options.Output == "" { gologger.Fatal().Msg("Please specify an output file using -o/-output when using -oa/-output-all") } diff --git a/runner/ports_optimization.go b/runner/ports_optimization.go new file mode 100644 index 000000000..4ccb9e71b --- /dev/null +++ b/runner/ports_optimization.go @@ -0,0 +1,33 @@ +package runner + +import ( + "net" + "strconv" + + "github.com/projectdiscovery/httpx/common/httpx" + sliceutil "github.com/projectdiscovery/utils/slice" +) + +var commonHttpPorts = []string{ + "80", + "8080", +} + +// determineMostLikelySchemeOrder for the input +func determineMostLikelySchemeOrder(input string) string { + if _, port, err := net.SplitHostPort(input); err == nil { + // if input has port that is commonly used for HTTP, return http then https + if sliceutil.Contains(commonHttpPorts, port) { + return httpx.HTTP + } + + // As of 10/2025 shodan shows that ports > 1024 are more likely to expose HTTP + // hence we test first http then https on higher ports + // if input has port > 1024, return http then https + if port, err := strconv.Atoi(port); err == nil && port > 1024 { + return httpx.HTTP + } + } + + return httpx.HTTPS +} diff --git a/runner/runner.go b/runner/runner.go index 4b47141b1..82df4fa10 100644 --- a/runner/runner.go +++ b/runner/runner.go @@ -39,8 +39,8 @@ import ( "github.com/projectdiscovery/httpx/static" "github.com/projectdiscovery/mapcidr/asn" "github.com/projectdiscovery/networkpolicy" - errorutil "github.com/projectdiscovery/utils/errors" osutil "github.com/projectdiscovery/utils/os" + "github.com/projectdiscovery/utils/structs" "github.com/Mzack9999/gcache" "github.com/logrusorgru/aurora" @@ -68,6 +68,7 @@ import ( "github.com/projectdiscovery/mapcidr" "github.com/projectdiscovery/rawhttp" converstionutil "github.com/projectdiscovery/utils/conversion" + errkit "github.com/projectdiscovery/utils/errkit" fileutil "github.com/projectdiscovery/utils/file" pdhttputil "github.com/projectdiscovery/utils/http" iputil "github.com/projectdiscovery/utils/ip" @@ -100,6 +101,9 @@ func (r *Runner) HTTPX() *httpx.HTTPX { // picked based on try-fail but it seems to close to one it's used https://www.hackerfactor.com/blog/index.php?/archives/432-Looks-Like-It.html#c1992 var hammingDistanceThreshold int = 22 +// regex for stripping ANSI codes +var ansiRegex = regexp.MustCompile(`\x1b\[[0-9;]*m`) + type pHashCluster struct { BasePHash uint64 `json:"base_phash,omitempty" csv:"base_phash"` Hashes []pHashUrl `json:"hashes,omitempty" csv:"hashes"` @@ -118,15 +122,20 @@ func New(options *Options) (*Runner, error) { if options.Wappalyzer != nil { runner.wappalyzer = options.Wappalyzer } else if options.TechDetect || options.JSONOutput || options.CSVOutput || options.AssetUpload { - runner.wappalyzer, err = wappalyzer.New() + runner.wappalyzer, err = func() (*wappalyzer.Wappalyze, error) { + if options.CustomFingerprintFile != "" { + return wappalyzer.NewFromFile(options.CustomFingerprintFile, true, true) + } + return wappalyzer.New() + }() } if err != nil { return nil, errors.Wrap(err, "could not create wappalyzer client") } if options.StoreResponseDir != "" { - os.RemoveAll(filepath.Join(options.StoreResponseDir, "response", "index.txt")) - os.RemoveAll(filepath.Join(options.StoreResponseDir, "screenshot", "index_screenshot.txt")) + _ = os.RemoveAll(filepath.Join(options.StoreResponseDir, "response", "index.txt")) + _ = os.RemoveAll(filepath.Join(options.StoreResponseDir, "screenshot", "index_screenshot.txt")) } httpxOptions := httpx.DefaultOptions @@ -168,6 +177,11 @@ func New(options *Options) (*Runner, error) { } else { httpxOptions.RandomAgent = options.RandomAgent } + if options.CustomHeaders.Has("Referer:") { + httpxOptions.AutoReferer = false + } else { + httpxOptions.AutoReferer = options.AutoReferer + } httpxOptions.ZTLS = options.ZTLS httpxOptions.MaxResponseBodySizeToSave = int64(options.MaxResponseBodySizeToSave) httpxOptions.MaxResponseBodySizeToRead = int64(options.MaxResponseBodySizeToRead) @@ -177,6 +191,7 @@ func New(options *Options) (*Runner, error) { } httpxOptions.Resolvers = options.Resolvers httpxOptions.TlsImpersonate = options.TlsImpersonate + httpxOptions.Protocol = httpx.Proto(options.Protocol) var key, value string httpxOptions.CustomHeaders = make(map[string]string) @@ -412,10 +427,27 @@ func (runner *Runner) createNetworkpolicyInstance(options *Options) (*networkpol npOptions.DenyList = append(npOptions.DenyList, exclude) } } + + npOptions.AllowList = appendToList(npOptions.AllowList, options.Allow...) + npOptions.DenyList = appendToList(npOptions.DenyList, options.Deny...) + np, err := networkpolicy.New(npOptions) return np, err } +func appendToList(list []string, values ...string) []string { + for _, value := range values { + switch { + case asn.IsASN(value): + ips := expandASNInputValue(value) + list = append(list, ips...) + default: + list = append(list, value) + } + } + return list +} + func expandCIDRInputValue(value string) []string { var ips []string ipsCh, _ := mapcidr.IPAddressesAsStream(value) @@ -673,7 +705,7 @@ func makePrintCallback() func(stats clistats.StatisticsClient) interface{} { builder.WriteString(clistats.String(uint64(incrementRequests / duration.Seconds()))) builder.WriteString(" | Requests: ") - builder.WriteString(fmt.Sprintf("%.0f", currentRequests)) + _, _ = fmt.Fprintf(builder, "%.0f", currentRequests) hosts, _ := stats.GetCounter("hosts") totalHosts, _ := stats.GetStatic("totalHosts") @@ -684,7 +716,6 @@ func makePrintCallback() func(stats clistats.StatisticsClient) interface{} { builder.WriteString(clistats.String(totalHosts)) builder.WriteRune(' ') builder.WriteRune('(') - //nolint:gomnd // this is not a magic number builder.WriteString(clistats.String(uint64(float64(hosts) / float64(totalHosts.(int)) * 100.0))) builder.WriteRune('%') builder.WriteRune(')') @@ -784,18 +815,26 @@ func (r *Runner) RunEnumeration() { if r.options.Output != "" && r.options.OutputAll { plainFile = openOrCreateFile(r.options.Resume, r.options.Output) - defer plainFile.Close() + defer func() { + _ = plainFile.Close() + }() jsonFile = openOrCreateFile(r.options.Resume, r.options.Output+".json") - defer jsonFile.Close() + defer func() { + _ = jsonFile.Close() + }() csvFile = openOrCreateFile(r.options.Resume, r.options.Output+".csv") - defer csvFile.Close() + defer func() { + _ = csvFile.Close() + }() } jsonOrCsv := (r.options.JSONOutput || r.options.CSVOutput) jsonAndCsv := (r.options.JSONOutput && r.options.CSVOutput) if r.options.Output != "" && plainFile == nil && !jsonOrCsv { plainFile = openOrCreateFile(r.options.Resume, r.options.Output) - defer plainFile.Close() + defer func() { + _ = plainFile.Close() + }() } if r.options.Output != "" && r.options.JSONOutput && jsonFile == nil { @@ -804,7 +843,9 @@ func (r *Runner) RunEnumeration() { ext = ".json" } jsonFile = openOrCreateFile(r.options.Resume, r.options.Output+ext) - defer jsonFile.Close() + defer func() { + _ = jsonFile.Close() + }() } if r.options.Output != "" && r.options.CSVOutput && csvFile == nil { @@ -813,7 +854,9 @@ func (r *Runner) RunEnumeration() { ext = ".csv" } csvFile = openOrCreateFile(r.options.Resume, r.options.Output+ext) - defer csvFile.Close() + defer func() { + _ = csvFile.Close() + }() } if r.options.CSVOutput { @@ -887,16 +930,6 @@ func (r *Runner) RunEnumeration() { continue } - if indexFile != nil && resp.Err == nil { - indexData := fmt.Sprintf("%s %s (%d %s)\n", resp.StoredResponsePath, resp.URL, resp.StatusCode, http.StatusText(resp.StatusCode)) - _, _ = indexFile.WriteString(indexData) - } - - if indexScreenshotFile != nil && resp.ScreenshotPathRel != "" { - indexData := fmt.Sprintf("%s %s (%d %s)\n", resp.ScreenshotPathRel, resp.URL, resp.StatusCode, http.StatusText(resp.StatusCode)) - _, _ = indexScreenshotFile.WriteString(indexData) - } - // apply matchers and filters if r.options.OutputFilterCondition != "" || r.options.OutputMatchCondition != "" { if r.options.OutputMatchCondition != "" { @@ -1076,7 +1109,7 @@ func (r *Runner) RunEnumeration() { // store response if r.scanopts.StoreResponse || r.scanopts.StoreChain { if r.scanopts.OmitBody { - resp.Raw = strings.Replace(resp.Raw, resp.ResponseBody, "", -1) + resp.Raw = strings.ReplaceAll(resp.Raw, resp.ResponseBody, "") } responsePath = fileutilz.AbsPathOrDefault(filepath.Join(responseBaseDir, domainResponseFile)) @@ -1150,7 +1183,13 @@ func (r *Runner) RunEnumeration() { //nolint:errcheck // this method needs a small refactor to reduce complexity if plainFile != nil { - plainFile.WriteString(resp.str + "\n") + plainFile.WriteString(handleStripAnsiCharacters(resp.str, r.options.NoColor) + "\n") + } + + if len(r.options.ExcludeOutputFields) > 0 { + if filteredData, err := structs.FilterStruct(resp, nil, r.options.ExcludeOutputFields); err == nil { + resp = filteredData + } } // call the callback function if any @@ -1204,7 +1243,9 @@ func (r *Runner) RunEnumeration() { if err != nil { gologger.Warning().Msgf("Could not create HTML file %s\n", err) } - defer screenshotHtml.Close() + defer func() { + _ = screenshotHtml.Close() + }() templateMap := template.FuncMap{ "safeURL": func(u string) template.URL { @@ -1296,7 +1337,9 @@ func (r *Runner) RunEnumeration() { if err != nil { gologger.Fatal().Msgf("Failed to create JSON file: %v", err) } - defer file.Close() + defer func() { + _ = file.Close() + }() _, err = file.Write(clusterReportJSON) if err != nil { @@ -1305,6 +1348,13 @@ func (r *Runner) RunEnumeration() { } } +func handleStripAnsiCharacters(data string, skip bool) string { + if skip { + return data + } + return stripANSI(data) +} + func logFilteredErrorPage(fileName, url string) { dir := filepath.Dir(fileName) if !fileutil.FolderExists(dir) { @@ -1320,7 +1370,9 @@ func logFilteredErrorPage(fileName, url string) { gologger.Fatal().Msgf("Could not open/create output file '%s': %s\n", fileName, err) return } - defer file.Close() + defer func() { + _ = file.Close() + }() info := map[string]interface{}{ "url": url, @@ -1527,7 +1579,7 @@ func (r *Runner) targets(hp *httpx.HTTPX, target string) chan httpx.Target { func (r *Runner) analyze(hp *httpx.HTTPX, protocol string, target httpx.Target, method, origInput string, scanopts *ScanOptions) Result { origProtocol := protocol if protocol == httpx.HTTPorHTTPS || protocol == httpx.HTTPandHTTPS { - protocol = httpx.HTTPS + protocol = determineMostLikelySchemeOrder(target.Host) } retried := false retry: @@ -1621,7 +1673,7 @@ retry: var requestDump []byte if scanopts.Unsafe { var errDump error - requestDump, errDump = rawhttp.DumpRequestRaw(req.Method, req.URL.String(), reqURI, req.Header, req.Body, rawhttp.DefaultOptions) + requestDump, errDump = rawhttp.DumpRequestRaw(req.Method, req.String(), reqURI, req.Header, req.Body, rawhttp.DefaultOptions) if errDump != nil { return Result{URL: URL.String(), Input: origInput, Err: errDump} } @@ -1644,7 +1696,7 @@ retry: } } // fix the final output url - fullURL := req.URL.String() + fullURL := req.String() if parsedURL, errParse := r.parseURL(fullURL); errParse != nil { return Result{URL: URL.String(), Input: origInput, Err: errParse} } else { @@ -1830,7 +1882,7 @@ retry: serverHeader := resp.GetHeader("Server") if scanopts.OutputServerHeader { - builder.WriteString(fmt.Sprintf(" [%s]", serverHeader)) + _, _ = fmt.Fprintf(builder, " [%s]", serverHeader) } var ( @@ -1838,6 +1890,7 @@ retry: request string rawResponseHeaders string responseHeaders map[string]interface{} + linkRequest []NetworkRequest ) if scanopts.ResponseHeadersInStdout { @@ -1944,7 +1997,7 @@ retry: } if scanopts.OutputIP || scanopts.ProbeAllIPS { - builder.WriteString(fmt.Sprintf(" [%s]", ip)) + _, _ = fmt.Fprintf(builder, " [%s]", ip) } var onlyHost string @@ -1969,16 +2022,16 @@ retry: if scanopts.OutputCName && len(cnames) > 0 { // Print only the first CNAME (full list in json) - builder.WriteString(fmt.Sprintf(" [%s]", cnames[0])) + _, _ = fmt.Fprintf(builder, " [%s]", cnames[0]) } isCDN, cdnName, cdnType, err := hp.CdnCheck(ip) if scanopts.OutputCDN == "true" && isCDN && err == nil { - builder.WriteString(fmt.Sprintf(" [%s]", cdnName)) + _, _ = fmt.Fprintf(builder, " [%s]", cdnName) } if scanopts.OutputResponseTime { - builder.WriteString(fmt.Sprintf(" [%s]", resp.Duration)) + _, _ = fmt.Fprintf(builder, " [%s]", resp.Duration) } technologyDetails := make(map[string]wappalyzer.AppInfo) @@ -2042,7 +2095,7 @@ retry: hashesMap := make(map[string]interface{}) if scanopts.Hashes != "" { hs := strings.Split(scanopts.Hashes, ",") - outputHashes := !(r.options.JSONOutput || r.options.OutputAll) + outputHashes := !(r.options.JSONOutput || r.options.OutputAll) //nolint if outputHashes { builder.WriteString(" [") } @@ -2095,7 +2148,7 @@ retry: if !scanopts.OutputWithNoColor { builder.WriteString(aurora.Magenta(resp.Lines).String()) } else { - builder.WriteString(fmt.Sprint(resp.Lines)) + _, _ = fmt.Fprintf(builder, "%d", resp.Lines) } builder.WriteRune(']') } @@ -2106,7 +2159,7 @@ retry: if !scanopts.OutputWithNoColor { builder.WriteString(aurora.Magenta(jarmhash).String()) } else { - builder.WriteString(fmt.Sprint(jarmhash)) + _, _ = fmt.Fprintf(builder, "%s", jarmhash) } builder.WriteRune(']') } @@ -2115,7 +2168,7 @@ retry: if !scanopts.OutputWithNoColor { builder.WriteString(aurora.Magenta(resp.Words).String()) } else { - builder.WriteString(fmt.Sprint(resp.Words)) + _, _ = fmt.Fprintf(builder, "%d", resp.Words) } builder.WriteRune(']') } @@ -2133,7 +2186,7 @@ retry: // store response if scanopts.StoreResponse || scanopts.StoreChain { if r.options.OmitBody { - resp.Raw = strings.Replace(resp.Raw, string(resp.Data), "", -1) + resp.Raw = strings.ReplaceAll(resp.Raw, string(resp.Data), "") } responsePath = fileutilz.AbsPathOrDefault(filepath.Join(responseBaseDir, domainResponseFile)) // URL.EscapedString returns that can be used as filename @@ -2190,7 +2243,14 @@ retry: var pHash uint64 if scanopts.Screenshot { var err error - screenshotBytes, headlessBody, err = r.browser.ScreenshotWithBody(fullURL, scanopts.ScreenshotTimeout, scanopts.ScreenshotIdle, r.options.CustomHeaders, scanopts.IsScreenshotFullPage()) + screenshotBytes, headlessBody, linkRequest, err = r.browser.ScreenshotWithBody( + fullURL, + scanopts.ScreenshotTimeout, + scanopts.ScreenshotIdle, + r.options.CustomHeaders, + scanopts.IsScreenshotFullPage(), + r.options.JavascriptCodes, + ) if err != nil { gologger.Warning().Msgf("Could not take screenshot '%s': %s", fullURL, err) } else { @@ -2235,6 +2295,7 @@ retry: result := Result{ Timestamp: time.Now(), Request: request, + LinkRequest: linkRequest, ResponseHeaders: responseHeaders, RawHeaders: rawResponseHeaders, Scheme: parsed.Scheme, @@ -2336,9 +2397,9 @@ func calculatePerceptionHash(screenshotBytes []byte) (uint64, error) { func (r *Runner) HandleFaviconHash(hp *httpx.HTTPX, req *retryablehttp.Request, currentResp []byte, finalURL string, defaultProbe bool) (string, string, string, []byte, string, error) { // Check if current URI is ending with .ico => use current body without additional requests - if path.Ext(req.URL.Path) == ".ico" { + if path.Ext(req.Path) == ".ico" { mmh3, md5h, err := r.calculateFaviconHashWithRaw(currentResp) - return mmh3, md5h, req.URL.Path, currentResp, req.URL.String(), err + return mmh3, md5h, req.Path, currentResp, req.String(), err } // Parse HTML: collect hrefs + optional @@ -2353,7 +2414,7 @@ func (r *Runner) HandleFaviconHash(hp *httpx.HTTPX, req *retryablehttp.Request, } // Determine base URL: prefer finalURL (redirect target) then apply - baseNet, _ := url.Parse(req.URL.String()) + baseNet, _ := url.Parse(req.String()) if finalURL != "" { if u, err := url.Parse(finalURL); err == nil { baseNet = u @@ -2441,7 +2502,7 @@ func (r *Runner) HandleFaviconHash(hp *httpx.HTTPX, req *retryablehttp.Request, faviconMMH3 = mmh3 faviconMD5 = md5h faviconPath = raw - faviconURL = clone.URL.String() + faviconURL = clone.String() faviconData = respFav.Data gologger.Debug().Msgf("favicon resolved url=%s raw_href=%s size=%d bytes", faviconURL, faviconPath, len(faviconData)) break @@ -2453,7 +2514,7 @@ func (r *Runner) HandleFaviconHash(hp *httpx.HTTPX, req *retryablehttp.Request, func (r *Runner) calculateFaviconHashWithRaw(data []byte) (string, string, error) { hashNum, md5Hash, err := stringz.FaviconHash(data) if err != nil { - return "", "", errorutil.NewWithTag("favicon", "could not calculate favicon hash").Wrap(err) + return "", "", errkit.Wrapf(err, "could not calculate favicon hash") } return fmt.Sprintf("%d", hashNum), md5Hash, nil } @@ -2655,3 +2716,8 @@ func isWebSocket(resp *httpx.Response) bool { } return false } + +// stripANSI removes ANSI color codes from a string using pre-compiled regex +func stripANSI(str string) string { + return ansiRegex.ReplaceAllString(str, "") +} diff --git a/runner/runner_test.go b/runner/runner_test.go index f88e012fb..850566b8d 100644 --- a/runner/runner_test.go +++ b/runner/runner_test.go @@ -222,3 +222,93 @@ func TestRunner_CSVRow(t *testing.T) { t.Error("CSV sanitization incorrectly modified non-vulnerable field") } } + +func TestCreateNetworkpolicyInstance_AllowDenyFlags(t *testing.T) { + runner := &Runner{} + + tests := []struct { + name string + allow []string + deny []string + testCases []struct { + ip string + expected bool + reason string + } + }{ + { + name: "Allow flag blocks IPs outside allowed range", + allow: []string{"192.168.1.0/24"}, + deny: nil, + testCases: []struct { + ip string + expected bool + reason string + }{ + {"8.8.8.8", false, "IP outside allowed range should be blocked"}, + {"192.168.1.10", true, "IP inside allowed range should be allowed"}, + }, + }, + { + name: "Deny flag blocks IPs in denied range", + allow: nil, + deny: []string{"127.0.0.0/8"}, + testCases: []struct { + ip string + expected bool + reason string + }{ + {"127.0.0.1", false, "IP in denied range should be blocked"}, + {"8.8.8.8", true, "IP outside denied range should be allowed"}, + }, + }, + { + name: "Combined Allow and Deny flags", + allow: []string{"192.168.0.0/16"}, + deny: []string{"192.168.1.0/24"}, + testCases: []struct { + ip string + expected bool + reason string + }{ + {"10.0.0.1", false, "IP outside allowed range should be blocked"}, + {"192.168.1.100", false, "IP in denied range should be blocked even if in allowed range"}, + {"192.168.2.50", true, "IP in allowed range but not in denied range should be allowed"}, + }, + }, + { + name: "Multiple Allow and Deny ranges", + allow: []string{"10.0.0.0/8", "172.16.0.0/12"}, + deny: []string{"10.1.0.0/16", "172.20.0.0/16"}, + testCases: []struct { + ip string + expected bool + reason string + }{ + {"10.0.1.1", true, "10.0.1.1 should be allowed (in allow range, not in deny)"}, + {"10.1.1.1", false, "10.1.1.1 should be blocked (in deny range)"}, + {"172.16.1.1", true, "172.16.1.1 should be allowed (in allow range, not in deny)"}, + {"172.20.1.1", false, "172.20.1.1 should be blocked (in deny range)"}, + {"192.168.1.1", false, "192.168.1.1 should be blocked (not in any allow range)"}, + }, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + options := &Options{ + Allow: tc.allow, + Deny: tc.deny, + } + + np, err := runner.createNetworkpolicyInstance(options) + require.Nil(t, err, "could not create networkpolicy instance") + require.NotNil(t, np, "networkpolicy instance should not be nil") + + for _, testCase := range tc.testCases { + allowed := np.Validate(testCase.ip) + require.Equal(t, testCase.expected, allowed, testCase.reason) + } + }) + } +} diff --git a/runner/types.go b/runner/types.go index 724e8697e..eb8456126 100644 --- a/runner/types.go +++ b/runner/types.go @@ -34,6 +34,7 @@ func (o AsnResponse) String() string { // Result of a scan type Result struct { Timestamp time.Time `json:"timestamp,omitempty" csv:"timestamp" mapstructure:"timestamp"` + LinkRequest []NetworkRequest `json:"link_request,omitempty" csv:"link_request" mapstructure:"link_request"` ASN *AsnResponse `json:"asn,omitempty" csv:"-" mapstructure:"asn"` Err error `json:"-" csv:"-" mapstructure:"-"` CSPData *httpx.CSPData `json:"csp,omitempty" csv:"-" mapstructure:"csp"` diff --git a/snapcraft.yaml b/snapcraft.yaml index 9f4b4f0b7..bdb337d8b 100644 --- a/snapcraft.yaml +++ b/snapcraft.yaml @@ -2,7 +2,7 @@ name: httpx summary: httpx is a fast and multi-purpose HTTP toolkit description: | httpx is a fast and multi-purpose HTTP toolkit allow to run multiple probers using retryablehttp library, it is designed to maintain the result reliability with increased threads. -version: 'v1.7.1' +version: 'v1.7.2' icon: static/httpx-logo.png license: MIT base: core18