package disk import ( "fmt" "io/fs" "os" "path/filepath" "strings" "github.com/pkg/errors" "github.com/projectdiscovery/nuclei/v3/pkg/catalog/config" fileutil "github.com/projectdiscovery/utils/file" urlutil "github.com/projectdiscovery/utils/url" ) // ResolvePath resolves the path to an absolute one in various ways. // // It checks if the filename is an absolute path, looks in the current directory // or checking the nuclei templates directory. If a second path is given, // it also tries to find paths relative to that second path. func (c *DiskCatalog) ResolvePath(templateName, second string) (string, error) { if filepath.IsAbs(templateName) { return templateName, nil } if c.templatesFS != nil { if potentialPath, err := c.tryResolve(templateName); err != errNoValidCombination { return potentialPath, nil } } if second != "" { secondBasePath := filepath.Join(filepath.Dir(second), templateName) if potentialPath, err := c.tryResolve(secondBasePath); err != errNoValidCombination { return potentialPath, nil } } if c.templatesFS == nil { curDirectory, err := os.Getwd() if err != nil { return "", err } templatePath := filepath.Join(curDirectory, templateName) if potentialPath, err := c.tryResolve(templatePath); err != errNoValidCombination { return potentialPath, nil } } templatePath := filepath.Join(config.DefaultConfig.GetTemplateDir(), templateName) if potentialPath, err := c.tryResolve(templatePath); err != errNoValidCombination { return potentialPath, nil } return "", fmt.Errorf("no such path found: %s", templateName) } var errNoValidCombination = errors.New("no valid combination found") // tryResolve attempts to load locate the target by iterating across all the folders tree func (c *DiskCatalog) tryResolve(fullPath string) (string, error) { if c.templatesFS == nil { if fileutil.FileOrFolderExists(fullPath) { return fullPath, nil } } else { if _, err := fs.Stat(c.templatesFS, fullPath); err == nil { return fullPath, nil } } return "", errNoValidCombination } // BackwardsCompatiblePaths returns new paths for all old/legacy template paths // Note: this is a temporary function and will be removed in the future release func BackwardsCompatiblePaths(templateDir string, oldPath string) string { // TODO: remove this function in the future release // 1. all http related paths are now moved at path /http // 2. network related CVES are now moved at path /network/cves newPathCallback := func(path string) string { // trim prefix slash if any path = strings.TrimPrefix(path, "/") // try to resolve path at /http subdirectory if fileutil.FileOrFolderExists(filepath.Join(templateDir, "http", path)) { return filepath.Join(templateDir, "http", path) // try to resolve path at /network/cves subdirectory } else if strings.HasPrefix(path, "cves") && fileutil.FileOrFolderExists(filepath.Join(templateDir, "network", "cves", path)) { return filepath.Join(templateDir, "network", "cves", path) } // most likely the path is not found return filepath.Join(templateDir, path) } switch { case fileutil.FileOrFolderExists(oldPath): // new path specified skip processing return oldPath case filepath.IsAbs(oldPath): tmp := strings.TrimPrefix(oldPath, templateDir) if tmp == oldPath { // user provided absolute path which is not in template directory // skip processing return oldPath } // trim the template directory from the path return newPathCallback(tmp) case strings.Contains(oldPath, urlutil.SchemeSeparator): // scheme separator is used to identify the path as url // TBD: add support for url directories ?? return oldPath case strings.Contains(oldPath, "*"): // this is most likely a glob path skip processing return oldPath default: // this is most likely a relative path return newPathCallback(oldPath) } }