github.com/projectdiscovery/nuclei/v2@v2.9.15/internal/installer/versioncheck.go (about)

     1  package installer
     2  
     3  import (
     4  	"encoding/json"
     5  	"io"
     6  	"net/url"
     7  	"os"
     8  	"runtime"
     9  
    10  	"github.com/projectdiscovery/nuclei/v2/pkg/catalog/config"
    11  	"github.com/projectdiscovery/retryablehttp-go"
    12  	updateutils "github.com/projectdiscovery/utils/update"
    13  )
    14  
    15  const (
    16  	pdtmNucleiVersionEndpoint    = "https://api.pdtm.sh/api/v1/tools/nuclei"
    17  	pdtmNucleiIgnoreFileEndpoint = "https://api.pdtm.sh/api/v1/tools/nuclei/ignore"
    18  )
    19  
    20  // defaultHttpClient is http client that is only meant to be used for version check
    21  // if proxy env variables are set those are reflected in this client
    22  var retryableHttpClient = retryablehttp.NewClient(retryablehttp.Options{HttpClient: updateutils.DefaultHttpClient, RetryMax: 2})
    23  
    24  // PdtmAPIResponse is the response from pdtm API for nuclei endpoint
    25  type PdtmAPIResponse struct {
    26  	IgnoreHash string `json:"ignore-hash"`
    27  	Tools      []struct {
    28  		Name    string `json:"name"`
    29  		Version string `json:"version"`
    30  	} `json:"tools"`
    31  }
    32  
    33  // NucleiVersionCheck checks for the latest version of nuclei and nuclei templates
    34  // and returns an error if it fails to check on success it returns nil and changes are
    35  // made to the default config in config.DefaultConfig
    36  func NucleiVersionCheck() error {
    37  	resp, err := retryableHttpClient.Get(pdtmNucleiVersionEndpoint + "?" + getpdtmParams())
    38  	if err != nil {
    39  		return err
    40  	}
    41  	defer resp.Body.Close()
    42  	bin, err := io.ReadAll(resp.Body)
    43  	if err != nil {
    44  		return err
    45  	}
    46  	var pdtmResp PdtmAPIResponse
    47  	if err := json.Unmarshal(bin, &pdtmResp); err != nil {
    48  		return err
    49  	}
    50  	var nucleiversion, templateversion string
    51  	for _, tool := range pdtmResp.Tools {
    52  		switch tool.Name {
    53  		case "nuclei":
    54  			if tool.Version != "" {
    55  				nucleiversion = "v" + tool.Version
    56  			}
    57  
    58  		case "nuclei-templates":
    59  			if tool.Version != "" {
    60  				templateversion = "v" + tool.Version
    61  			}
    62  		}
    63  	}
    64  	return config.DefaultConfig.WriteVersionCheckData(pdtmResp.IgnoreHash, nucleiversion, templateversion)
    65  }
    66  
    67  // getpdtmParams returns encoded query parameters sent to update check endpoint
    68  func getpdtmParams() string {
    69  	params := &url.Values{}
    70  	params.Add("os", runtime.GOOS)
    71  	params.Add("arch", runtime.GOARCH)
    72  	params.Add("go_version", runtime.Version())
    73  	params.Add("v", config.Version)
    74  	params.Add("utm_source", getUtmSource())
    75  	return params.Encode()
    76  }
    77  
    78  // UpdateIgnoreFile updates default ignore file by downloading latest ignore file
    79  func UpdateIgnoreFile() error {
    80  	resp, err := retryableHttpClient.Get(pdtmNucleiIgnoreFileEndpoint + "?" + getpdtmParams())
    81  	if err != nil {
    82  		return err
    83  	}
    84  	bin, err := io.ReadAll(resp.Body)
    85  	if err != nil {
    86  		return err
    87  	}
    88  	if err := os.WriteFile(config.DefaultConfig.GetIgnoreFilePath(), bin, 0644); err != nil {
    89  		return err
    90  	}
    91  	return config.DefaultConfig.UpdateNucleiIgnoreHash()
    92  }