/
search.go
173 lines (162 loc) · 5.41 KB
/
search.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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
package cmd
import (
"fmt"
"github.com/cheggaaa/pb"
"github.com/olekukonko/tablewriter"
"github.com/rs/zerolog/log"
"github.com/spf13/cobra"
"github.com/y4ney/collect-cnnvd-vuln/internal/cnnvd"
"github.com/y4ney/collect-cnnvd-vuln/internal/utils"
"os"
)
const (
QueryVulnList = "vuln"
QueryVendor = "vendor"
QueryProduct = "product"
RetryNum = 5
)
var (
Keyword string
Retry int
PageIndex int
PageSize int
HazardLevel string
Product string
Vendor string
)
var (
level = map[string]string{"超危": "1", "高危": "2", "中危": "3", "低危": "4"}
severity = map[int]string{0: "未知", 1: "超危", 2: "高危", 3: "中危", 4: "低危"}
searchCmd = &cobra.Command{
Use: "search",
Short: "搜索 CNNVD 漏洞信息",
Run: runSearchVuln,
}
)
func init() {
searchCmd.Flags().StringVarP(&Type, "type", "t", QueryVulnList, fmt.Sprintf("指定类型,仅支持 %s, %s 和 %s", QueryVulnList, QueryVendor, QueryProduct))
searchCmd.Flags().StringVarP(&Keyword, "keyword", "k", "", "指定搜索的关键词")
searchCmd.Flags().IntVarP(&Retry, "retry", "r", RetryNum, "指定请求的重试次数")
searchCmd.Flags().IntVar(&PageIndex, "page-index", cnnvd.FirstPage, "指定当前的页码,仅在 --type=vuln 时有效")
searchCmd.Flags().IntVar(&PageSize, "page-size", cnnvd.MaxPageSize, "指定页数大小 仅在 --type=vuln 时有效")
searchCmd.Flags().StringVar(&HazardLevel, "hazard-level", "", "指定威胁等级,仅支持 超危、高危、中危和低危, 仅在 --type=vuln 时有效")
// TODO 优化
searchCmd.Flags().StringVar(&Product, "product", "", "指定商品编号,仅在 --type=vuln 时有效,请先通过 --type=product 来获取商品编号")
searchCmd.Flags().StringVar(&Vendor, "vendor", "", "指定供应商编号,仅在 --type=vuln 时有效,请先通过 --type=vendor 获取供应商编号 ")
utils.BindFlags(searchCmd)
}
func runSearchVuln(_ *cobra.Command, _ []string) {
switch Type {
case QueryProduct:
searchProduct()
case QueryVendor:
searchVendor()
case QueryVulnList:
searchVuln()
default:
log.Error().Msgf("type %s is not supported", Type)
}
}
func searchProduct() {
c := cnnvd.ReqProduct{ProductKeyword: Keyword}
products, err := c.Fetch(Retry)
if err != nil {
log.Fatal().Str("keyword", Keyword).Int("retry", Retry).
Msgf("failed to search products:%v", err)
}
if len(products) == 0 {
log.Info().Str("keyword", Keyword).Int("retry", Retry).
Msg("there is no record")
return
}
var data [][]string
for _, product := range products {
data = append(data, []string{product.Label, product.Value})
}
printInfo([]string{"LABEL", "VALUE"}, data)
}
func searchVendor() {
c := cnnvd.ReqVendor{VendorKeyword: Keyword}
vendors, err := c.Fetch(Retry)
if err != nil {
log.Fatal().Str("keyword", Keyword).Int("retry", Retry).
Msgf("failed to search vendors:%v", err)
}
if len(vendors) == 0 {
log.Info().Str("keyword", Keyword).Int("retry", Retry).
Msg("there is no record")
return
}
var data [][]string
for _, product := range vendors {
data = append(data, []string{product.Label, product.Value})
}
printInfo([]string{"LABEL", "VALUE"}, data)
}
func searchVuln() {
c := cnnvd.ReqVulList{
PageIndex: PageIndex,
PageSize: PageSize,
Keyword: Keyword,
HazardLevel: level[HazardLevel],
Vendor: Vendor,
Product: Product,
}
vulns, err := c.Fetch(Retry)
if err != nil {
log.Fatal().Interface("request", c).Int("retry", Retry).
Msgf("failed to search vulns:%v", err)
}
log.Info().Interface("request", c).Int("retry", Retry).
Msg("success to request... ...")
if len(vulns) == 0 {
log.Info().Interface("request", c).Int("retry", Retry).
Msg("there is no record")
return
}
bar := pb.StartNew(len(vulns))
var data [][]string
for _, vuln := range vulns {
detailC := cnnvd.ReqVulDetail{Id: vuln.Id, VulType: vuln.VulType, CnnvdCode: vuln.CnnvdCode}
detail, err := detailC.Fetch(Retry)
log.Debug().Interface("request", detailC).Int("retry", Retry).
Msg("success to request... ...")
if err != nil {
log.Fatal().Interface("request", detailC).Int("retry", Retry).
Msgf("failed to search vuln detail:%v", err)
}
data = append(data, []string{severity[detail.HazardLevel], detail.CnnvdCode, detail.CveCode, detail.VulName,
detail.VulTypeName, detail.AffectedVendor, detail.AffectedProduct, detail.UpdateTime})
bar.Increment()
}
bar.Finish()
printInfo([]string{"SEVERITY", "CNNVD ID", "CVE ID", "NAME", "TYPE", "VENDOR", "PRODUCT", "UPDATE TIME"}, data)
}
func printInfo(header []string, data [][]string) {
table := tablewriter.NewWriter(os.Stdout)
table.SetHeader(header)
table.SetAlignment(tablewriter.ALIGN_LEFT)
table.SetAutoMergeCells(true)
table.SetRowLine(true)
for _, row := range data {
colors := make([]tablewriter.Colors, len(row))
for i, cell := range row {
switch cell {
case severity[0]:
colors[i] = tablewriter.Colors{tablewriter.Bold, tablewriter.FgBlackColor}
case severity[1]:
colors[i] = tablewriter.Colors{tablewriter.Bold, tablewriter.FgHiRedColor}
case severity[2]:
colors[i] = tablewriter.Colors{tablewriter.Bold, tablewriter.FgRedColor}
case severity[3]:
colors[i] = tablewriter.Colors{tablewriter.Bold, tablewriter.FgHiYellowColor}
case severity[4]:
colors[i] = tablewriter.Colors{tablewriter.Bold, tablewriter.FgHiBlueColor}
default:
colors[i] = tablewriter.Colors{}
}
}
table.Rich(row, colors)
}
table.Render()
}