Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
projectdiscovery
GitHub Repository: projectdiscovery/nuclei
Path: blob/dev/pkg/authprovider/file.go
2070 views
1
package authprovider
2
3
import (
4
"net"
5
"net/url"
6
"regexp"
7
"strings"
8
9
"github.com/projectdiscovery/nuclei/v3/pkg/authprovider/authx"
10
"github.com/projectdiscovery/utils/errkit"
11
urlutil "github.com/projectdiscovery/utils/url"
12
)
13
14
// FileAuthProvider is an auth provider for file based auth
15
// it accepts a secrets file and returns its provider
16
type FileAuthProvider struct {
17
Path string
18
store *authx.Authx
19
compiled map[*regexp.Regexp][]authx.AuthStrategy
20
domains map[string][]authx.AuthStrategy
21
}
22
23
// NewFileAuthProvider creates a new file based auth provider
24
func NewFileAuthProvider(path string, callback authx.LazyFetchSecret) (AuthProvider, error) {
25
store, err := authx.GetAuthDataFromFile(path)
26
if err != nil {
27
return nil, err
28
}
29
if len(store.Secrets) == 0 && len(store.Dynamic) == 0 {
30
return nil, ErrNoSecrets
31
}
32
if len(store.Dynamic) > 0 && callback == nil {
33
return nil, errkit.New("lazy fetch callback is required for dynamic secrets")
34
}
35
for _, secret := range store.Secrets {
36
if err := secret.Validate(); err != nil {
37
errorErr := errkit.FromError(err)
38
errorErr.Msgf("invalid secret in file: %s", path)
39
return nil, errorErr
40
}
41
}
42
for i, dynamic := range store.Dynamic {
43
if err := dynamic.Validate(); err != nil {
44
errorErr := errkit.FromError(err)
45
errorErr.Msgf("invalid dynamic in file: %s", path)
46
return nil, errorErr
47
}
48
dynamic.SetLazyFetchCallback(callback)
49
store.Dynamic[i] = dynamic
50
}
51
f := &FileAuthProvider{Path: path, store: store}
52
f.init()
53
return f, nil
54
}
55
56
// init initializes the file auth provider
57
func (f *FileAuthProvider) init() {
58
for _, _secret := range f.store.Secrets {
59
secret := _secret // allocate copy of pointer
60
if len(secret.DomainsRegex) > 0 {
61
for _, domain := range secret.DomainsRegex {
62
if f.compiled == nil {
63
f.compiled = make(map[*regexp.Regexp][]authx.AuthStrategy)
64
}
65
compiled, err := regexp.Compile(domain)
66
if err != nil {
67
continue
68
}
69
70
if ss, ok := f.compiled[compiled]; ok {
71
f.compiled[compiled] = append(ss, secret.GetStrategy())
72
} else {
73
f.compiled[compiled] = []authx.AuthStrategy{secret.GetStrategy()}
74
}
75
}
76
}
77
for _, domain := range secret.Domains {
78
if f.domains == nil {
79
f.domains = make(map[string][]authx.AuthStrategy)
80
}
81
domain = strings.TrimSpace(domain)
82
domain = strings.TrimSuffix(domain, ":80")
83
domain = strings.TrimSuffix(domain, ":443")
84
if ss, ok := f.domains[domain]; ok {
85
f.domains[domain] = append(ss, secret.GetStrategy())
86
} else {
87
f.domains[domain] = []authx.AuthStrategy{secret.GetStrategy()}
88
}
89
}
90
}
91
for _, dynamic := range f.store.Dynamic {
92
domain, domainsRegex := dynamic.GetDomainAndDomainRegex()
93
94
if len(domainsRegex) > 0 {
95
for _, domain := range domainsRegex {
96
if f.compiled == nil {
97
f.compiled = make(map[*regexp.Regexp][]authx.AuthStrategy)
98
}
99
compiled, err := regexp.Compile(domain)
100
if err != nil {
101
continue
102
}
103
if ss, ok := f.compiled[compiled]; !ok {
104
f.compiled[compiled] = []authx.AuthStrategy{&authx.DynamicAuthStrategy{Dynamic: dynamic}}
105
} else {
106
f.compiled[compiled] = append(ss, &authx.DynamicAuthStrategy{Dynamic: dynamic})
107
}
108
}
109
}
110
for _, domain := range domain {
111
if f.domains == nil {
112
f.domains = make(map[string][]authx.AuthStrategy)
113
}
114
domain = strings.TrimSpace(domain)
115
domain = strings.TrimSuffix(domain, ":80")
116
domain = strings.TrimSuffix(domain, ":443")
117
118
if ss, ok := f.domains[domain]; !ok {
119
f.domains[domain] = []authx.AuthStrategy{&authx.DynamicAuthStrategy{Dynamic: dynamic}}
120
} else {
121
f.domains[domain] = append(ss, &authx.DynamicAuthStrategy{Dynamic: dynamic})
122
}
123
}
124
}
125
}
126
127
// LookupAddr looks up a given domain/address and returns appropriate auth strategy
128
func (f *FileAuthProvider) LookupAddr(addr string) []authx.AuthStrategy {
129
var strategies []authx.AuthStrategy
130
131
if strings.Contains(addr, ":") {
132
// default normalization for host:port
133
host, port, err := net.SplitHostPort(addr)
134
if err == nil && (port == "80" || port == "443") {
135
addr = host
136
}
137
}
138
for domain, strategy := range f.domains {
139
if strings.EqualFold(domain, addr) {
140
strategies = append(strategies, strategy...)
141
}
142
}
143
for compiled, strategy := range f.compiled {
144
if compiled.MatchString(addr) {
145
strategies = append(strategies, strategy...)
146
}
147
}
148
149
return strategies
150
}
151
152
// LookupURL looks up a given URL and returns appropriate auth strategy
153
func (f *FileAuthProvider) LookupURL(u *url.URL) []authx.AuthStrategy {
154
return f.LookupAddr(u.Host)
155
}
156
157
// LookupURLX looks up a given URL and returns appropriate auth strategy
158
func (f *FileAuthProvider) LookupURLX(u *urlutil.URL) []authx.AuthStrategy {
159
return f.LookupAddr(u.Host)
160
}
161
162
// GetTemplatePaths returns the template path for the auth provider
163
func (f *FileAuthProvider) GetTemplatePaths() []string {
164
res := []string{}
165
for _, dynamic := range f.store.Dynamic {
166
if dynamic.TemplatePath != "" {
167
res = append(res, dynamic.TemplatePath)
168
}
169
}
170
return res
171
}
172
173
// PreFetchSecrets pre-fetches the secrets from the auth provider
174
func (f *FileAuthProvider) PreFetchSecrets() error {
175
for _, ss := range f.domains {
176
for _, s := range ss {
177
if val, ok := s.(*authx.DynamicAuthStrategy); ok {
178
if err := val.Dynamic.Fetch(false); err != nil {
179
return err
180
}
181
}
182
}
183
}
184
for _, ss := range f.compiled {
185
for _, s := range ss {
186
if val, ok := s.(*authx.DynamicAuthStrategy); ok {
187
if err := val.Dynamic.Fetch(false); err != nil {
188
return err
189
}
190
}
191
}
192
}
193
return nil
194
}
195
196