Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
projectdiscovery
GitHub Repository: projectdiscovery/nuclei
Path: blob/dev/pkg/js/devtools/tsgen/scrape.go
2070 views
1
package tsgen
2
3
import (
4
"fmt"
5
"go/types"
6
"regexp"
7
"strings"
8
9
"github.com/projectdiscovery/utils/errkit"
10
)
11
12
// scrape.go scrapes all information of exported type from different package
13
14
func (p *EntityParser) scrapeAndCreate(typeName string) error {
15
if p.newObjects[typeName] == nil {
16
return nil
17
}
18
// get package name
19
pkgName := strings.Split(typeName, ".")[0]
20
baseTypeName := strings.Split(typeName, ".")[1]
21
// get package
22
pkg, ok := p.imports[pkgName]
23
if !ok {
24
return errkit.Newf("package %v for type %v not found", pkgName, typeName)
25
}
26
// get type
27
obj := pkg.Types.Scope().Lookup(baseTypeName)
28
if obj == nil {
29
return errkit.Newf("type %v not found in package %+v", typeName, pkg)
30
}
31
// Ensure the object is a type name
32
typeNameObj, ok := obj.(*types.TypeName)
33
if !ok {
34
return errkit.Newf("%v is not a type name", typeName)
35
}
36
// Ensure the type is a named struct type
37
namedStruct, ok := typeNameObj.Type().Underlying().(*types.Struct)
38
if !ok {
39
return fmt.Errorf("%s is not a named struct type", typeName)
40
}
41
// fmt.Printf("got named struct %v\n", namedStruct)
42
// Iterate over the struct fields
43
d := &ExtObject{
44
builtIn: make(map[string]string),
45
nested: map[string]map[string]*ExtObject{},
46
}
47
48
// fmt.Printf("fields %v\n", namedStruct.NumFields())
49
for i := 0; i < namedStruct.NumFields(); i++ {
50
field := namedStruct.Field(i)
51
fieldName := field.Name()
52
if field.Exported() {
53
recursiveScrapeType(nil, fieldName, field.Type(), d)
54
}
55
}
56
entityMap := make(map[string]Entity)
57
// convert ExtObject to Entity
58
properties := ConvertExtObjectToEntities(d, entityMap)
59
entityMap[baseTypeName] = Entity{
60
Name: baseTypeName,
61
Type: "interface",
62
Description: fmt.Sprintf("%v Interface", baseTypeName),
63
Object: Interface{
64
Properties: properties,
65
},
66
}
67
68
for _, entity := range entityMap {
69
p.entities = append(p.entities, entity)
70
}
71
72
return nil
73
}
74
75
type ExtObject struct {
76
builtIn map[string]string
77
nested map[string]map[string]*ExtObject // Changed to map of field names to ExtObject
78
}
79
80
func recursiveScrapeType(parentType types.Type, fieldName string, fieldType types.Type, extObject *ExtObject) {
81
if named, ok := fieldType.(*types.Named); ok && !named.Obj().Exported() {
82
// fmt.Printf("type %v is not exported\n", named.Obj().Name())
83
return
84
}
85
86
if fieldType.String() == "time.Time" {
87
extObject.builtIn[fieldName] = "Date"
88
return
89
}
90
91
switch t := fieldType.Underlying().(type) {
92
case *types.Pointer:
93
// fmt.Printf("type %v is a pointer\n", fieldType)
94
recursiveScrapeType(nil, fieldName, t.Elem(), extObject)
95
case *types.Signature:
96
// fmt.Printf("type %v is a callback or interface\n", fieldType)
97
case *types.Basic:
98
// Check for basic types (built-in types)
99
if parentType != nil {
100
switch p := parentType.Underlying().(type) {
101
case *types.Slice:
102
extObject.builtIn[fieldName] = "[]" + fieldType.String()
103
case *types.Array:
104
extObject.builtIn[fieldName] = fmt.Sprintf("[%v]", p.Len()) + fieldType.String()
105
}
106
} else {
107
extObject.builtIn[fieldName] = fieldType.String()
108
}
109
case *types.Struct:
110
// Check for struct types
111
if extObject.nested[fieldName] == nil {
112
// @tarunKoyalwar: it currently does not supported struct arrays
113
extObject.nested[fieldName] = make(map[string]*ExtObject)
114
}
115
nestedExtObject := &ExtObject{
116
builtIn: make(map[string]string),
117
nested: map[string]map[string]*ExtObject{},
118
}
119
extObject.nested[fieldName][fieldType.String()] = nestedExtObject
120
for i := 0; i < t.NumFields(); i++ {
121
field := t.Field(i)
122
if field.Exported() {
123
recursiveScrapeType(nil, field.Name(), field.Type(), nestedExtObject)
124
}
125
}
126
case *types.Array:
127
// fmt.Printf("type %v is an array\n", fieldType)
128
// get array type
129
recursiveScrapeType(t, fieldName, t.Elem(), extObject)
130
case *types.Slice:
131
// fmt.Printf("type %v is a slice\n", fieldType)
132
// get slice type
133
recursiveScrapeType(t, fieldName, t.Elem(), extObject)
134
default:
135
// fmt.Printf("type %v is not a builtIn or struct\n", fieldType)
136
}
137
}
138
139
var re = regexp.MustCompile(`\[[0-9]+\].*`)
140
141
// ConvertExtObjectToEntities recursively converts an ExtObject to a list of Entity objects
142
func ConvertExtObjectToEntities(extObj *ExtObject, nestedTypes map[string]Entity) []Property {
143
var properties []Property
144
145
// Iterate over the built-in types
146
for fieldName, fieldType := range extObj.builtIn {
147
var description string
148
if re.MatchString(fieldType) {
149
// if it is a fixed size array add len in description
150
description = fmt.Sprintf("fixed size array of length: %v", fieldType[:strings.Index(fieldType, "]")+1])
151
// remove length from type
152
fieldType = "[]" + fieldType[strings.Index(fieldType, "]")+1:]
153
}
154
if strings.Contains(fieldType, "time.Duration") {
155
description = "time in nanoseconds"
156
}
157
px := Property{
158
Name: fieldName,
159
Type: toTsTypes(fieldType),
160
Description: description,
161
}
162
163
if strings.HasPrefix(px.Type, "[") {
164
px.Type = fieldType[strings.Index(px.Type, "]")+1:] + "[]"
165
}
166
properties = append(properties, px)
167
}
168
169
// Iterate over the nested types
170
for fieldName, nestedExtObjects := range extObj.nested {
171
for origType, nestedExtObject := range nestedExtObjects {
172
// fix:me this nestedExtObject always has only one element
173
got := ConvertExtObjectToEntities(nestedExtObject, nestedTypes)
174
baseTypename := origType[strings.LastIndex(origType, ".")+1:]
175
// create new nestedType
176
nestedTypes[baseTypename] = Entity{
177
Name: baseTypename,
178
Description: fmt.Sprintf("%v Interface", baseTypename),
179
Type: "interface",
180
Object: Interface{
181
Properties: got,
182
},
183
}
184
// assign current field type to nested type
185
properties = append(properties, Property{
186
Name: fieldName,
187
Type: baseTypename,
188
})
189
}
190
}
191
return properties
192
}
193
194