Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
projectdiscovery
GitHub Repository: projectdiscovery/nuclei
Path: blob/dev/pkg/catalog/disk/find.go
2838 views
1
package disk
2
3
import (
4
"fmt"
5
"io/fs"
6
"os"
7
"path/filepath"
8
"strings"
9
10
"github.com/logrusorgru/aurora"
11
"github.com/pkg/errors"
12
"github.com/projectdiscovery/nuclei/v3/pkg/catalog/config"
13
stringsutil "github.com/projectdiscovery/utils/strings"
14
updateutils "github.com/projectdiscovery/utils/update"
15
urlutil "github.com/projectdiscovery/utils/url"
16
)
17
18
var deprecatedPathsCounter int
19
20
// GetTemplatesPath returns a list of absolute paths for the provided template list.
21
func (c *DiskCatalog) GetTemplatesPath(definitions []string) ([]string, map[string]error) {
22
// keeps track of processed dirs and files
23
processed := make(map[string]bool)
24
allTemplates := []string{}
25
erred := make(map[string]error)
26
27
for _, t := range definitions {
28
if stringsutil.ContainsAny(t, knownConfigFiles...) {
29
// TODO: this is a temporary fix to avoid treating these files as templates
30
// this should be replaced with more appropriate and robust logic
31
continue
32
}
33
if strings.Contains(t, urlutil.SchemeSeparator) && stringsutil.ContainsAny(t, config.GetSupportTemplateFileExtensions()...) {
34
if _, ok := processed[t]; !ok {
35
processed[t] = true
36
allTemplates = append(allTemplates, t)
37
}
38
} else {
39
paths, err := c.GetTemplatePath(t)
40
if err != nil {
41
erred[t] = err
42
}
43
for _, path := range paths {
44
if _, ok := processed[path]; !ok {
45
processed[path] = true
46
allTemplates = append(allTemplates, path)
47
}
48
}
49
}
50
}
51
// purge all false positives
52
filteredTemplates := []string{}
53
for _, v := range allTemplates {
54
// TODO: this is a temporary fix to avoid treating these files as templates
55
// this should be replaced with more appropriate and robust logic
56
if !stringsutil.ContainsAny(v, knownConfigFiles...) {
57
filteredTemplates = append(filteredTemplates, v)
58
}
59
}
60
61
return filteredTemplates, erred
62
}
63
64
// GetTemplatePath parses the specified input template path and returns a compiled
65
// list of finished absolute paths to the templates evaluating any glob patterns
66
// or folders provided as in.
67
func (c *DiskCatalog) GetTemplatePath(target string) ([]string, error) {
68
processed := make(map[string]struct{})
69
70
if c.templatesFS == nil {
71
var err error
72
target, err = c.convertPathToAbsolute(target)
73
if err != nil {
74
return nil, errors.Wrapf(err, "could not find template file")
75
}
76
}
77
78
if strings.Contains(target, "*") {
79
globMatches, err := c.findGlobPathMatches(target, processed)
80
if err != nil {
81
return nil, errors.Wrap(err, "could not globbing path")
82
}
83
84
if len(globMatches) > 0 {
85
return globMatches, nil
86
} else {
87
return globMatches, fmt.Errorf("%w in path %q", ErrNoTemplatesFound, target)
88
}
89
}
90
91
// `target` is either a file or a directory
92
match, file, err := c.findFileMatches(target, processed)
93
if err != nil {
94
return nil, errors.Wrap(err, "could not find file")
95
}
96
97
if file {
98
if match != "" {
99
return []string{match}, nil
100
}
101
return nil, nil
102
}
103
104
// Recursively walk down the Templates directory and run all
105
// the template file checks
106
matches, err := c.findDirectoryMatches(target, processed)
107
if err != nil {
108
return nil, errors.Wrap(err, "could not find directory matches")
109
}
110
111
if len(matches) == 0 {
112
return nil, fmt.Errorf("%w in path %q", ErrNoTemplatesFound, target)
113
}
114
115
return matches, nil
116
}
117
118
// convertPathToAbsolute resolves the paths provided to absolute paths
119
// before doing any operations on them regardless of them being BLOB, folders, files, etc.
120
func (c *DiskCatalog) convertPathToAbsolute(t string) (string, error) {
121
if strings.Contains(t, "*") {
122
file := filepath.Base(t)
123
absPath, err := c.ResolvePath(filepath.Dir(t), "")
124
if err != nil {
125
return "", err
126
}
127
return filepath.Join(absPath, file), nil
128
}
129
return c.ResolvePath(t, "")
130
}
131
132
// findGlobPathMatches returns the matched files from a glob path
133
func (c *DiskCatalog) findGlobPathMatches(absPath string, processed map[string]struct{}) ([]string, error) {
134
// trim templateDir if any
135
relPath := strings.TrimPrefix(absPath, c.templatesDirectory)
136
// trim leading slash if any
137
if c.templatesFS != nil {
138
// fs.FS always uses forward slashes
139
relPath = strings.TrimPrefix(relPath, "/")
140
} else {
141
relPath = strings.TrimPrefix(relPath, string(os.PathSeparator))
142
}
143
144
var err error
145
var matches []string
146
147
if c.templatesFS != nil {
148
matches, err = fs.Glob(c.templatesFS, relPath)
149
} else {
150
matches, err = filepath.Glob(absPath)
151
}
152
153
if err != nil {
154
return nil, err
155
}
156
157
results := make([]string, 0, len(matches))
158
for _, match := range matches {
159
if _, ok := processed[match]; !ok {
160
processed[match] = struct{}{}
161
results = append(results, match)
162
}
163
}
164
165
return results, nil
166
}
167
168
// findFileMatches finds if a path is an absolute file. If the path
169
// is a file, it returns true otherwise false with no errors.
170
func (c *DiskCatalog) findFileMatches(absPath string, processed map[string]struct{}) (match string, matched bool, err error) {
171
if c.templatesFS != nil {
172
absPath = strings.Trim(absPath, "/")
173
}
174
var info fs.File
175
if c.templatesFS == nil {
176
info, err = os.Open(absPath)
177
} else {
178
// If we were given no path, then it's not a file, it's the root, and we can quietly return.
179
if absPath == "" {
180
return "", false, nil
181
}
182
183
info, err = c.templatesFS.Open(absPath)
184
}
185
if err != nil {
186
return "", false, err
187
}
188
stat, err := info.Stat()
189
if err != nil {
190
return "", false, err
191
}
192
if !stat.Mode().IsRegular() {
193
return "", false, nil
194
}
195
if _, ok := processed[absPath]; !ok {
196
processed[absPath] = struct{}{}
197
return absPath, true, nil
198
}
199
return "", true, nil
200
}
201
202
// findDirectoryMatches finds matches for templates from a directory
203
func (c *DiskCatalog) findDirectoryMatches(absPath string, processed map[string]struct{}) ([]string, error) {
204
var results []string
205
var err error
206
if c.templatesFS == nil {
207
err = filepath.WalkDir(
208
absPath,
209
func(path string, d fs.DirEntry, err error) error {
210
// continue on errors
211
if err != nil {
212
return nil
213
}
214
if !d.IsDir() && config.IsTemplateWithRoot(path, absPath) {
215
if _, ok := processed[path]; !ok {
216
results = append(results, path)
217
processed[path] = struct{}{}
218
}
219
}
220
return nil
221
},
222
)
223
} else {
224
// For the special case of the root directory, we need to pass "." to `fs.WalkDir`.
225
if absPath == "" {
226
absPath = "."
227
}
228
absPath = strings.TrimSuffix(absPath, "/")
229
230
err = fs.WalkDir(
231
c.templatesFS,
232
absPath,
233
func(path string, d fs.DirEntry, err error) error {
234
// continue on errors
235
if err != nil {
236
return nil
237
}
238
if !d.IsDir() && config.IsTemplateWithRoot(path, absPath) {
239
if _, ok := processed[path]; !ok {
240
results = append(results, path)
241
processed[path] = struct{}{}
242
}
243
}
244
return nil
245
},
246
)
247
}
248
return results, err
249
}
250
251
// PrintDeprecatedPathsMsgIfApplicable prints a warning message if any
252
// deprecated paths are found. Unless mode is silent warning message is printed.
253
//
254
// Deprecated: No longer used since the official Nuclei Templates repository
255
// have restructured this a long time ago.
256
func PrintDeprecatedPathsMsgIfApplicable(isSilent bool) {
257
if !updateutils.IsOutdated("v9.4.3", config.DefaultConfig.TemplateVersion) {
258
return
259
}
260
if deprecatedPathsCounter > 0 && !isSilent {
261
config.DefaultConfig.Logger.Print().Msgf("[%v] Found %v template[s] loaded with deprecated paths, update before v3 for continued support.\n", aurora.Yellow("WRN").String(), deprecatedPathsCounter)
262
}
263
}
264
265