forked from aquasecurity/trivy-java-db
/
pomutils.go
120 lines (101 loc) · 3.06 KB
/
pomutils.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
package crawler
import (
"encoding/xml"
"io"
"net/http"
"strings"
"golang.org/x/net/html/charset"
"golang.org/x/xerrors"
)
type PomParsedValues struct {
Licenses []string
Dependencies []Dependency
}
type PomProject struct {
GroupID string `xml:"groupId"`
ArtifactID string `xml:"artifactId"`
Version string `xml:"version"`
Name string `xml:"name"`
Description string `xml:"description"`
URL string `xml:"url"`
Licenses []License `xml:"licenses>license"`
Dependencies []Dependency `xml:"dependencies>dependency"`
Properties properties `xml:"properties"`
}
type property struct {
XMLName xml.Name
Value string `xml:",chardata"`
}
type properties map[string]string
func (props *properties) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
*props = properties{}
for {
var p property
err := d.Decode(&p)
if err == io.EOF {
break
} else if err != nil {
return err
}
(*props)[p.XMLName.Local] = p.Value
}
return nil
}
func substitutePlaceholders(project *PomProject) {
for key, value := range project.Properties {
placeholder := "${" + key + "}"
// Substitute placeholders in dependencies
for i := range project.Dependencies {
project.Dependencies[i].GroupID = strings.ReplaceAll(project.Dependencies[i].GroupID, placeholder, value)
project.Dependencies[i].ArtifactID = strings.ReplaceAll(project.Dependencies[i].ArtifactID, placeholder, value)
project.Dependencies[i].Version = strings.ReplaceAll(project.Dependencies[i].Version, placeholder, value)
}
}
}
type License struct {
Name string `xml:"name"`
URL string `xml:"url"`
LicenseKey string
ClassificationConfidence float64
}
type Dependency struct {
GroupID string `xml:"groupId"`
ArtifactID string `xml:"artifactId"`
Version string `xml:"version"`
Text string `xml:",chardata"`
Scope string `xml:"scope"`
Optional bool `xml:"optional"`
}
func preprocessXML(xmlData string) (string, error) {
// Remove all hr tags
xmlData = strings.ReplaceAll(xmlData, "<hr>", "")
xmlData = strings.ReplaceAll(xmlData, "</hr>", "")
return xmlData, nil
}
func parseAndSubstitutePom(url string) (PomProject, error) {
var project PomProject
resp, err := http.Get(url)
if resp.StatusCode == http.StatusNotFound {
return project, nil
}
if err != nil {
return project, xerrors.Errorf("can't get pom xml from %s: %w", url, err)
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return project, xerrors.Errorf("error reading response body from %s: %w", url, err)
}
xmlData, err := preprocessXML(string(body))
if err != nil {
return project, xerrors.Errorf("error preprocessing xml from %s: %w", url, err)
}
decoder := xml.NewDecoder(strings.NewReader(xmlData))
decoder.CharsetReader = charset.NewReaderLabel
err = decoder.Decode(&project)
if err != nil {
return project, xerrors.Errorf("error decoding pom.xml from %s: %w", url, err)
}
substitutePlaceholders(&project)
return project, nil
}