package installer
import (
"bufio"
"bytes"
"fmt"
"io"
"io/fs"
"net/http"
"os"
"path/filepath"
"sort"
"github.com/Masterminds/semver/v3"
"github.com/projectdiscovery/gologger"
"github.com/projectdiscovery/nuclei/v3/pkg/catalog/config"
"github.com/projectdiscovery/utils/errkit"
)
func GetNewTemplatesInVersions(versions ...string) []string {
allTemplates := []string{}
for _, v := range versions {
if v == config.DefaultConfig.TemplateVersion {
allTemplates = append(allTemplates, config.DefaultConfig.GetNewAdditions()...)
}
_, err := semver.NewVersion(v)
if err != nil {
gologger.Error().Msgf("%v is not a valid semver version. skipping", v)
continue
}
if config.IsOutdatedVersion(v, "v8.8.4") {
gologger.Error().Msgf(".new-additions support was added in v8.8.4 older versions are not supported")
continue
}
arr, err := getNewAdditionsFileFromGitHub(v)
if err != nil {
gologger.Error().Msgf("failed to fetch new additions for %v got: %v", v, err)
continue
}
allTemplates = append(allTemplates, arr...)
}
return allTemplates
}
func getNewAdditionsFileFromGitHub(version string) ([]string, error) {
resp, err := retryableHttpClient.Get(fmt.Sprintf("https://raw.githubusercontent.com/projectdiscovery/nuclei-templates/%s/.new-additions", version))
if err != nil {
return nil, err
}
if resp.StatusCode != http.StatusOK {
return nil, errkit.New("version not found")
}
data, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
templatesList := []string{}
scanner := bufio.NewScanner(bytes.NewReader(data))
for scanner.Scan() {
text := scanner.Text()
if text == "" {
continue
}
if config.IsTemplate(text) {
templatesList = append(templatesList, text)
}
}
return templatesList, nil
}
func PurgeEmptyDirectories(dir string) {
alldirs := []string{}
_ = filepath.WalkDir(dir, func(path string, d fs.DirEntry, err error) error {
if d.IsDir() {
alldirs = append(alldirs, path)
}
return nil
})
sort.Strings(alldirs)
sort.Sort(sort.Reverse(sort.StringSlice(alldirs)))
for _, d := range alldirs {
if isEmptyDir(d) {
_ = os.RemoveAll(d)
}
}
}
func isEmptyDir(dir string) bool {
hasFiles := false
_ = filepath.WalkDir(dir, func(path string, d fs.DirEntry, err error) error {
if !d.IsDir() {
hasFiles = true
return io.EOF
}
return nil
})
return !hasFiles
}