/* ·━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━· : : : █▀ █ █▀▀ · Blazing-fast pentesting suite : : ▄█ █ █▀ · BSD 3-Clause License : : : : (c) 2022-2026 vmfunc, xyzeva, : : lunchcat alumni & contributors : : : ·━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━· */ package scan import ( "context" "os" "sync" "time" "github.com/charmbracelet/log" nuclei "github.com/projectdiscovery/nuclei/v3/lib" "github.com/projectdiscovery/nuclei/v3/pkg/output" "github.com/vmfunc/sif/internal/nuclei/format" "github.com/vmfunc/sif/internal/nuclei/templates" sifoutput "github.com/vmfunc/sif/internal/output" ) func Nuclei(url string, timeout time.Duration, threads int, logdir string) ([]output.ResultEvent, error) { sifoutput.ScanStart("nuclei template scanning") spin := sifoutput.NewSpinner("Running nuclei templates") spin.Start() nucleilog := log.NewWithOptions(os.Stderr, log.Options{ Prefix: "nuclei", }).With("url", url) _ = templates.Install(nucleilog) pwd, err := os.Getwd() if err != nil { spin.Stop() return nil, err } ctx := context.Background() ne, err := nuclei.NewNucleiEngineCtx(ctx, nuclei.WithTemplatesOrWorkflows(nuclei.TemplateSources{ Templates: []string{pwd + "/nuclei-templates"}, }), nuclei.WithConcurrency(nuclei.Concurrency{ TemplateConcurrency: threads, HostConcurrency: 1, HeadlessHostConcurrency: 1, HeadlessTemplateConcurrency: 1, JavascriptTemplateConcurrency: 1, TemplatePayloadConcurrency: 25, ProbeConcurrency: 50, }), nuclei.WithNetworkConfig(nuclei.NetworkConfig{ Timeout: int(timeout.Seconds()), }), nuclei.DisableUpdateCheck(), ) if err != nil { spin.Stop() return nil, err } defer ne.Close() sanitizedURL := stripScheme(url) ne.LoadTargets([]string{sanitizedURL}, false) var results []output.ResultEvent var mu sync.Mutex err = ne.ExecuteCallbackWithCtx(ctx, func(event *output.ResultEvent) { if event.Matched != "" { nucleilog.Infof("%s", format.FormatLine(event)) mu.Lock() results = append(results, *event) mu.Unlock() } }) spin.Stop() sifoutput.ScanComplete("nuclei template scanning", len(results), "found") return results, err }