-
Notifications
You must be signed in to change notification settings - Fork 55
/
Copy pathformatter_excel.go
177 lines (147 loc) · 3.56 KB
/
formatter_excel.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
174
175
176
177
package formatter
import (
"fmt"
"github.com/xuri/excelize/v2"
)
// ExcelColWidth is the default width of the columns in the Excel file
var ExcelColWidth float64 = 50
// ExcelFormatter is struct defined for Excel Output use-case
type ExcelFormatter struct {
config *Config
}
// CellData is a struct to hold the data for a cell to avoid code duplication
type CellData struct {
sheetName string
style int
file *excelize.File
}
func (cd *CellData) writeCell(cell string, value string) error {
err := cd.file.SetCellValue(cd.sheetName, cell, value)
if err != nil {
return err
}
return cd.file.SetCellStyle(cd.sheetName, cell, cell, cd.style)
}
// Format the data to Excel and output it to an Excel file
func (f *ExcelFormatter) Format(td *TemplateData, templateContent string) (err error) {
file := excelize.NewFile()
sheetName := "Sheet1"
// Create a style for center alignment
style, err := file.NewStyle(&excelize.Style{
Alignment: &excelize.Alignment{
Horizontal: "center",
Vertical: "center",
WrapText: true,
},
})
if err != nil {
return err
}
// Reusable cell data struct for writing cells
cd := &CellData{
sheetName: sheetName,
style: style,
file: file,
}
// Set column headers with titles
err = f.writeHeaders(cd)
if err != nil {
return err
}
err = f.writeHostRows(td.NMAPRun.Host, cd)
if err != nil {
return err
}
return file.Write(f.config.Writer, excelize.Options{})
}
func (f *ExcelFormatter) writeHostRows(h []Host, cd *CellData) error {
var err error
row := 2 // Start from row 2 for data
for i := range h {
host := h[i]
if host.ShouldSkipHost(f.config.OutputOptions.ExcelOptions.SkipDownHosts) {
continue
}
joinedAddresses := host.JoinedAddresses("/")
joinedHostnames := host.JoinedHostNames("/")
addressFormat := "%s [%s]"
address := ""
if joinedHostnames == "" {
address = fmt.Sprintf(addressFormat, joinedAddresses, host.Status.State)
} else {
addressFormat = "%s (%s) [%s]"
address = fmt.Sprintf(
addressFormat,
joinedAddresses,
joinedHostnames,
host.Status.State,
)
}
// Set the IP/Host value
cell := fmt.Sprintf("A%d", row)
err = cd.writeCell(cell, address)
if err != nil {
return err
}
startRow := row // Remember the start row for this host
err = f.writePorts(host.Port, cd, &row)
if err != nil {
return err
}
// Merge cells in the IP/Host column for this host
if row > startRow+1 {
err = cd.file.MergeCell(
cd.sheetName,
fmt.Sprintf("A%d", startRow),
fmt.Sprintf("A%d", row-1),
)
if err != nil {
return err
}
}
}
return err
}
func (f *ExcelFormatter) writePorts(p []Port, cd *CellData, row *int) error {
var err error
// The case when there are no open ports
if len(p) == 0 {
err = cd.writeCell(
fmt.Sprintf("%c%d", 'B', *row),
"-",
)
if err != nil {
return err
}
*row++
return nil
}
for i := range p {
port := p[i]
// Set the Service value for column B for services
err = cd.writeCell(
fmt.Sprintf("%c%d", 'B', *row),
fmt.Sprintf("%d/%s %s", port.PortID, port.Protocol, port.Service.Name),
)
if err != nil {
return err
}
*row++
}
return err
}
func (f *ExcelFormatter) writeHeaders(cd *CellData) error {
err := cd.writeCell("A1", "IP/Host")
if err != nil {
return err
}
// Setting the width of the columns in order not to cut the text
err = cd.file.SetColWidth(cd.sheetName, "A", "B", ExcelColWidth)
if err != nil {
return err
}
return cd.writeCell("B1", "Services")
}
func (f *ExcelFormatter) defaultTemplateContent() string {
return ""
}