初版
This commit is contained in:
8
.idea/.gitignore
generated
vendored
Normal file
8
.idea/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
# 默认忽略的文件
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# 基于编辑器的 HTTP 客户端请求
|
||||
/httpRequests/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
||||
8
.idea/modules.xml
generated
Normal file
8
.idea/modules.xml
generated
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/rsasZipToExcel.iml" filepath="$PROJECT_DIR$/.idea/rsasZipToExcel.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
9
.idea/rsasZipToExcel.iml
generated
Normal file
9
.idea/rsasZipToExcel.iml
generated
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="WEB_MODULE" version="4">
|
||||
<component name="Go" enabled="true" />
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
6
.idea/vcs.xml
generated
Normal file
6
.idea/vcs.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
41
cmd/cmd.go
Normal file
41
cmd/cmd.go
Normal file
@@ -0,0 +1,41 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"rsasZipToExcel/pkg"
|
||||
)
|
||||
|
||||
func Runner() {
|
||||
//命令行
|
||||
var zipFile, outputFilename string
|
||||
|
||||
flag.StringVar(&zipFile, "z", "", "-z 包含漏洞的zip文件")
|
||||
flag.StringVar(&outputFilename, "o", "", "-o 输出的文件名")
|
||||
|
||||
flag.Parse()
|
||||
//拆分excel
|
||||
if outputFilename == "" {
|
||||
outputFilename = "output"
|
||||
}
|
||||
|
||||
//解析zip
|
||||
err := pkg.MergeRsasVulnToExcel(zipFile, outputFilename)
|
||||
if err != nil {
|
||||
print(err.Error())
|
||||
}
|
||||
//匹配excel
|
||||
|
||||
//合并输出
|
||||
}
|
||||
|
||||
//同比上个月漏洞情况
|
||||
|
||||
//初始化rsas
|
||||
|
||||
//初始化yb
|
||||
|
||||
//读取配置 yaml?
|
||||
|
||||
//定时扫描
|
||||
|
||||
//触发发送?
|
||||
27
go.mod
Normal file
27
go.mod
Normal file
@@ -0,0 +1,27 @@
|
||||
module rsasZipToExcel
|
||||
|
||||
go 1.17
|
||||
|
||||
require (
|
||||
github.com/antchfx/htmlquery v1.2.4
|
||||
github.com/schollz/progressbar/v3 v3.8.6
|
||||
github.com/xuri/excelize/v2 v2.6.0
|
||||
golang.org/x/net v0.0.0-20220407224826-aac1ed45d8e3
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/antchfx/xpath v1.2.0 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect
|
||||
github.com/mattn/go-runewidth v0.0.13 // indirect
|
||||
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirect
|
||||
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
|
||||
github.com/richardlehane/mscfb v1.0.4 // indirect
|
||||
github.com/richardlehane/msoleps v1.0.1 // indirect
|
||||
github.com/rivo/uniseg v0.2.0 // indirect
|
||||
github.com/xuri/efp v0.0.0-20220407160117-ad0f7a785be8 // indirect
|
||||
github.com/xuri/nfp v0.0.0-20220409054826-5e722a1d9e22 // indirect
|
||||
golang.org/x/crypto v0.0.0-20220408190544-5352b0902921 // indirect
|
||||
golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27 // indirect
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
|
||||
golang.org/x/text v0.3.7 // indirect
|
||||
)
|
||||
67
go.sum
Normal file
67
go.sum
Normal file
@@ -0,0 +1,67 @@
|
||||
github.com/antchfx/htmlquery v1.2.4 h1:qLteofCMe/KGovBI6SQgmou2QNyedFUW+pE+BpeZ494=
|
||||
github.com/antchfx/htmlquery v1.2.4/go.mod h1:2xO6iu3EVWs7R2JYqBbp8YzG50gj/ofqs5/0VZoDZLc=
|
||||
github.com/antchfx/xpath v1.2.0 h1:mbwv7co+x0RwgeGAOHdrKy89GvHaGvxxBtPK0uF9Zr8=
|
||||
github.com/antchfx/xpath v1.2.0/go.mod h1:i54GszH55fYfBmoZXapTHN8T8tkcHfRgLyVwwqzXNcs=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY=
|
||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213/go.mod h1:vNUNkEQ1e29fT/6vq2aBdFsgNPmy8qMdSay1npru+Sw=
|
||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||
github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU=
|
||||
github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db h1:62I3jR2EmQ4l5rM/4FEfDWcRD+abF5XlKShorW5LRoQ=
|
||||
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db/go.mod h1:l0dey0ia/Uv7NcFFVbCLtqEBQbrT4OCwCSKTEv6enCw=
|
||||
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw=
|
||||
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/richardlehane/mscfb v1.0.4 h1:WULscsljNPConisD5hR0+OyZjwK46Pfyr6mPu5ZawpM=
|
||||
github.com/richardlehane/mscfb v1.0.4/go.mod h1:YzVpcZg9czvAuhk9T+a3avCpcFPMUWm7gK3DypaEsUk=
|
||||
github.com/richardlehane/msoleps v1.0.1 h1:RfrALnSNXzmXLbGct/P2b4xkFz4e8Gmj/0Vj9M9xC1o=
|
||||
github.com/richardlehane/msoleps v1.0.1/go.mod h1:BWev5JBpU9Ko2WAgmZEuiz4/u3ZYTKbjLycmwiWUfWg=
|
||||
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
|
||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/schollz/progressbar/v3 v3.8.6 h1:QruMUdzZ1TbEP++S1m73OqRJk20ON11m6Wqv4EoGg8c=
|
||||
github.com/schollz/progressbar/v3 v3.8.6/go.mod h1:W5IEwbJecncFGBvuEh4A7HT1nZZ6WNIL2i3qbnI0WKY=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/xuri/efp v0.0.0-20220407160117-ad0f7a785be8 h1:3X7aE0iLKJ5j+tz58BpvIZkXNV7Yq4jC93Z/rbN2Fxk=
|
||||
github.com/xuri/efp v0.0.0-20220407160117-ad0f7a785be8/go.mod h1:ybY/Jr0T0GTCnYjKqmdwxyxn2BQf2RcQIIvex5QldPI=
|
||||
github.com/xuri/excelize/v2 v2.6.0 h1:m/aXAzSAqxgt74Nfd+sNzpzVKhTGl7+S9nbG4A57mF4=
|
||||
github.com/xuri/excelize/v2 v2.6.0/go.mod h1:Q1YetlHesXEKwGFfeJn7PfEZz2IvHb6wdOeYjBxVcVs=
|
||||
github.com/xuri/nfp v0.0.0-20220409054826-5e722a1d9e22 h1:OAmKAfT06//esDdpi/DZ8Qsdt4+M5+ltca05dA5bG2M=
|
||||
github.com/xuri/nfp v0.0.0-20220409054826-5e722a1d9e22/go.mod h1:WwHg+CVyzlv/TX9xqBFXEZAuxOPxn2k1GNHwG41IIUQ=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20220131195533-30dcbda58838/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.0.0-20220408190544-5352b0902921 h1:iU7T1X1J6yxDr0rda54sWGkHgOp5XJrqm79gcNlC2VM=
|
||||
golang.org/x/crypto v0.0.0-20220408190544-5352b0902921/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/image v0.0.0-20211028202545-6944b10bf410 h1:hTftEOvwiOq2+O8k2D5/Q7COC7k5Qcrgc2TFURJYnvQ=
|
||||
golang.org/x/image v0.0.0-20211028202545-6944b10bf410/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=
|
||||
golang.org/x/net v0.0.0-20200421231249-e086a090c8fd/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220407224826-aac1ed45d8e3 h1:EN5+DfgmRMvRUrMGERW2gQl3Vc+Z7ZMnI/xdEpPSf0c=
|
||||
golang.org/x/net v0.0.0-20220407224826-aac1ed45d8e3/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27 h1:XDXtA5hveEEV8JB2l7nhMTp3t3cHp9ZpwcdjqyEWLlo=
|
||||
golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
7
main.go
Normal file
7
main.go
Normal file
@@ -0,0 +1,7 @@
|
||||
package main
|
||||
|
||||
import "rsasZipToExcel/cmd"
|
||||
|
||||
func main() {
|
||||
cmd.Runner()
|
||||
}
|
||||
507
pkg/rsas.go
Normal file
507
pkg/rsas.go
Normal file
@@ -0,0 +1,507 @@
|
||||
package pkg
|
||||
|
||||
import (
|
||||
"archive/zip"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/antchfx/htmlquery"
|
||||
"github.com/schollz/progressbar/v3"
|
||||
"github.com/xuri/excelize/v2"
|
||||
"golang.org/x/net/html"
|
||||
"io"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func RsasInit() *RsasScanner {
|
||||
return &RsasScanner{}
|
||||
}
|
||||
|
||||
func (RsasScanner *RsasScanner) AnalyseZip(zipFile string) bool {
|
||||
//var filenames []string
|
||||
print("解析zip: " + zipFile)
|
||||
r, err := zip.OpenReader(zipFile)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
defer r.Close()
|
||||
var htmlAllVulnInfos []HtmlAllVulnInfo
|
||||
for _, f := range r.File {
|
||||
//println(f.Name)
|
||||
re := regexp.MustCompile(`host/.*?.html`)
|
||||
htmlFilename := re.FindAllString(f.Name, -1)
|
||||
if len(htmlFilename) >= 1 {
|
||||
|
||||
htmlContent := GetHtmlContent(f)
|
||||
if htmlContent != "" {
|
||||
htmlAllVulnInfo := QueryHtmlInfo(htmlContent)
|
||||
//for _, vuln := range htmlAllVulnInfo.HtmlVulnInfos {
|
||||
// fmt.Printf(vuln.Solution)
|
||||
//}
|
||||
htmlAllVulnInfos = append(htmlAllVulnInfos, htmlAllVulnInfo)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
for _, eachHtmlVuln := range htmlAllVulnInfos {
|
||||
for _, eachVuln := range eachHtmlVuln.HtmlVulnInfos {
|
||||
RsasScanner.AllVulnInfos = append(RsasScanner.AllVulnInfos, eachVuln)
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func MergeRsasVulnToExcel(zipFile string, outputFilename string) error {
|
||||
//print("执行中")
|
||||
if zipFile == "" {
|
||||
return errors.New("请输入压缩文件文件名, -h 弹出帮助菜单")
|
||||
}
|
||||
rsas := RsasInit()
|
||||
rsas.AnalyseZip(zipFile)
|
||||
rsas.GenerateXlsx(outputFilename)
|
||||
//fmt.Printf("%v", rsas.AllVulnInfos)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetHtmlContent(filename *zip.File) string {
|
||||
//println("打印..")
|
||||
htmlContent, err := filename.Open()
|
||||
if err != nil {
|
||||
println("解析html有问题")
|
||||
}
|
||||
//io流转string
|
||||
if b, err := io.ReadAll(htmlContent); err == nil {
|
||||
return string(b)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func QueryHtmlInfo(content string) (htmlAllVulnInfo HtmlAllVulnInfo) {
|
||||
//var htmlAllVulnInfo HtmlAllVulnInfo
|
||||
|
||||
doc, err := htmlquery.Parse(strings.NewReader(content))
|
||||
if err != nil {
|
||||
println(err)
|
||||
}
|
||||
|
||||
//println(htmlquery.InnerText(ip)) //ip
|
||||
ip := htmlquery.FindOne(doc, "//*[@id=\"content\"]/div[2]/table[2]/tbody/tr/td[1]/table/tbody/tr[1]/td")
|
||||
|
||||
if strings.Contains(content, "非常安全(0分)") {
|
||||
println(htmlquery.InnerText(ip) + " 无漏洞")
|
||||
} else {
|
||||
vulnDetail := htmlquery.FindOne(doc, "//*[@id=\"vuln_list\"]/tbody")
|
||||
|
||||
//ip := htmlquery.FindOne(doc, "//*[@id=\"content\"]/div[2]/table[2]/tbody/tr/td[1]/table/tbody/tr[1]/td")
|
||||
|
||||
nodes := htmlquery.Find(vulnDetail, "//tr")
|
||||
htmlAllVulnInfo = FindVulnDetails(nodes, ip)
|
||||
//htmlVulnInfo.IpAddress = htmlquery.InnerText(ip)
|
||||
//htmlAllVulnInfo.HtmlVulnInfos = append(htmlAllVulnInfo.HtmlVulnInfos, htmlVulnInfo)
|
||||
vulnSolutionNode := htmlquery.FindOne(doc, "//*[@id=\"vul_detail\"]/table")
|
||||
solutionVulnInfos := FindVulnSolution(vulnSolutionNode)
|
||||
for _, solutionVulnInfo := range solutionVulnInfos {
|
||||
for i, htmlVulnInfo := range htmlAllVulnInfo.HtmlVulnInfos {
|
||||
if htmlVulnInfo.VulnInfos == solutionVulnInfo.VulnInfos {
|
||||
//println("找到解决方法:" + htmlVulnInfo.VulnInfos)
|
||||
|
||||
htmlAllVulnInfo.HtmlVulnInfos[i].Solution = solutionVulnInfo.Solution
|
||||
htmlAllVulnInfo.HtmlVulnInfos[i].CVENumber = solutionVulnInfo.CVENumber
|
||||
htmlAllVulnInfo.HtmlVulnInfos[i].Details = solutionVulnInfo.Details
|
||||
htmlAllVulnInfo.HtmlVulnInfos[i].RiskLevel = solutionVulnInfo.RiskLevel
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return htmlAllVulnInfo
|
||||
}
|
||||
|
||||
func FindVulnDetails(nodes []*html.Node, ip *html.Node) HtmlAllVulnInfo {
|
||||
var htmlAllVulnInfo HtmlAllVulnInfo
|
||||
var htmlVulnInfo HtmlVulnInfo
|
||||
filterFirstLine := false
|
||||
for _, node := range nodes {
|
||||
if !filterFirstLine {
|
||||
filterFirstLine = true
|
||||
continue
|
||||
}
|
||||
|
||||
td := htmlquery.Find(node, "//td")
|
||||
htmlVulnInfo.IpAddress = htmlquery.InnerText(ip)
|
||||
htmlVulnInfo.Port = htmlquery.InnerText(td[0])
|
||||
htmlVulnInfo.Protocol = htmlquery.InnerText(td[1])
|
||||
htmlVulnInfo.Service = htmlquery.InnerText(td[2])
|
||||
if JudgeMutiVulnName(td[3]) {
|
||||
vulnInfos := AddMutiVulnName(td[3], htmlVulnInfo)
|
||||
for _, vulnInfo := range vulnInfos {
|
||||
htmlAllVulnInfo.HtmlVulnInfos = append(htmlAllVulnInfo.HtmlVulnInfos, vulnInfo)
|
||||
}
|
||||
} else {
|
||||
htmlVulnInfo.VulnInfos = htmlquery.InnerText(htmlquery.FindOne(td[3], "//span"))
|
||||
htmlVulnInfo.VulnInfos = strings.Replace(htmlVulnInfo.VulnInfos, "\r", "", -1)
|
||||
htmlVulnInfo.VulnInfos = strings.Replace(htmlVulnInfo.VulnInfos, "\n", "", -1)
|
||||
htmlVulnInfo.VulnInfos = strings.Replace(htmlVulnInfo.VulnInfos, " ", "", -1)
|
||||
versionDiv, _ := htmlquery.QueryAll(td[3], "//div/div")
|
||||
if len(versionDiv) == 0 {
|
||||
htmlVulnInfo.ServiceDetail = ""
|
||||
} else {
|
||||
//println("端口" + htmlVulnInfo.Port)
|
||||
//println(len(versionDiv))
|
||||
htmlVulnInfo.ServiceDetail = TrimString(htmlquery.InnerText(versionDiv[0]))
|
||||
|
||||
//println("单漏洞版本号: " + htmlVulnInfo.ServiceDetail)
|
||||
}
|
||||
|
||||
htmlVulnInfo.ServiceDetail = TrimString(htmlVulnInfo.ServiceDetail)
|
||||
htmlAllVulnInfo.HtmlVulnInfos = append(htmlAllVulnInfo.HtmlVulnInfos, htmlVulnInfo)
|
||||
}
|
||||
|
||||
//for _, n := range td {
|
||||
//
|
||||
// //text := strings.Replace(htmlquery.InnerText(n), "\r", "", -1)
|
||||
// //text = strings.Replace(text, "\n", "", -1)
|
||||
// //text = strings.Replace(text, " ", "", -1)
|
||||
// println(text)
|
||||
//}
|
||||
}
|
||||
return htmlAllVulnInfo
|
||||
}
|
||||
|
||||
func JudgeMutiVulnName(td *html.Node) bool {
|
||||
span := htmlquery.Find(td, "//span")
|
||||
if len(span) > 1 {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func AddMutiVulnName(td *html.Node, vulnInfo HtmlVulnInfo) (vulnInfos []HtmlVulnInfo) {
|
||||
|
||||
spans := htmlquery.Find(td, "//span")
|
||||
|
||||
for i, span := range spans {
|
||||
eachVulnInfo := HtmlVulnInfo{
|
||||
IpAddress: vulnInfo.IpAddress,
|
||||
Port: vulnInfo.Port,
|
||||
Service: vulnInfo.Service,
|
||||
Protocol: vulnInfo.Protocol,
|
||||
}
|
||||
//println("端口" + vulnInfo.Port)
|
||||
|
||||
versionDiv, _ := htmlquery.QueryAll(td, "//ul/li["+strconv.Itoa(i+1)+"]/div/div") ///html/body/div/div[4]/div[4]/div[2]/table/tbody/tr[8]/td[4]/ul/li[1]/div/div
|
||||
if len(versionDiv) == 0 {
|
||||
|
||||
eachVulnInfo.ServiceDetail = ""
|
||||
} else {
|
||||
|
||||
eachVulnInfo.ServiceDetail = TrimString(htmlquery.InnerText(versionDiv[0]))
|
||||
//eachVulnInfo.ServiceDetail = htmlquery.SelectAttr(versionDiv, "class")
|
||||
//println("多漏洞 版本号:" + eachVulnInfo.ServiceDetail)
|
||||
}
|
||||
|
||||
eachVulnInfo.VulnInfos = htmlquery.InnerText(span)
|
||||
eachVulnInfo.VulnInfos = strings.Replace(eachVulnInfo.VulnInfos, "\r", "", -1)
|
||||
eachVulnInfo.VulnInfos = strings.Replace(eachVulnInfo.VulnInfos, "\n", "", -1)
|
||||
eachVulnInfo.VulnInfos = strings.Replace(eachVulnInfo.VulnInfos, " ", "", -1)
|
||||
vulnInfos = append(vulnInfos, eachVulnInfo)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
//先提取所有漏洞修复,再根据漏洞名称分配至每个漏洞内。
|
||||
func FindVulnSolution(vulnSolutionNode *html.Node) (solutionVulninfos []HtmlVulnInfo) {
|
||||
var count int
|
||||
var solutionVulnInfo HtmlVulnInfo
|
||||
nodes := htmlquery.Find(vulnSolutionNode, "//tr")
|
||||
for _, node := range nodes {
|
||||
//匹配修复表格中漏洞名称
|
||||
trClass := htmlquery.SelectAttr(node, "data-id")
|
||||
if trClass != "" {
|
||||
vulnName := htmlquery.InnerText(htmlquery.FindOne(node, "//td//span"))
|
||||
vulnName = strings.Replace(vulnName, "\r", "", -1)
|
||||
vulnName = strings.Replace(vulnName, "\n", "", -1)
|
||||
vulnName = strings.Replace(vulnName, " ", "", -1)
|
||||
solutionVulnInfo.VulnInfos = vulnName
|
||||
//println(vulnName)
|
||||
//漏洞等级
|
||||
spanClass := htmlquery.FindOne(node, "//span")
|
||||
className := htmlquery.SelectAttr(spanClass, "class")
|
||||
if className != "" {
|
||||
className = strings.Split(className, "_")[2]
|
||||
solutionVulnInfo.RiskLevel = GetChineseRiskLevel(className)
|
||||
//println(solutionVulnInfo.RiskLevel)
|
||||
}
|
||||
count += 1
|
||||
}
|
||||
|
||||
trsolutionClass := htmlquery.SelectAttr(node, "class")
|
||||
if trsolutionClass == "solution" || trsolutionClass == "solution hide" {
|
||||
trsolutionTable := htmlquery.FindOne(node, "//table")
|
||||
GetSolutionInfo(trsolutionTable, &solutionVulnInfo)
|
||||
count += 1
|
||||
}
|
||||
if count == 2 {
|
||||
count = 0
|
||||
solutionVulninfos = append(solutionVulninfos, solutionVulnInfo)
|
||||
solutionVulnInfo = HtmlVulnInfo{}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func GetChineseRiskLevel(level string) (chineseLevel string) {
|
||||
if level == "low" {
|
||||
return "低"
|
||||
}
|
||||
if level == "middle" {
|
||||
return "中"
|
||||
}
|
||||
if level == "high" {
|
||||
return "高"
|
||||
}
|
||||
return "未定级"
|
||||
}
|
||||
|
||||
func GetSolutionInfo(htmlTable *html.Node, solutionVulnInfo *HtmlVulnInfo) {
|
||||
tr := htmlquery.Find(htmlTable, "//tr")
|
||||
for _, line := range tr {
|
||||
th := htmlquery.FindOne(line, "//th")
|
||||
|
||||
if htmlquery.InnerText(th) == "详细描述" {
|
||||
td := htmlquery.FindOne(line, "//td")
|
||||
text := htmlquery.InnerText(td)
|
||||
text = strings.Replace(text, "\r", "", -1)
|
||||
text = strings.Replace(text, "\n", "", -1)
|
||||
text = strings.Replace(text, " ", "", -1)
|
||||
solutionVulnInfo.Details = text
|
||||
}
|
||||
|
||||
if htmlquery.InnerText(th) == "解决办法" {
|
||||
td := htmlquery.FindOne(line, "//td")
|
||||
text := htmlquery.InnerText(td)
|
||||
text = strings.Replace(text, "\r", "", -1)
|
||||
text = strings.Replace(text, "\n", "", -1)
|
||||
text = strings.Replace(text, " ", "", -1)
|
||||
solutionVulnInfo.Solution = text
|
||||
}
|
||||
if htmlquery.InnerText(th) == "CVE编号" {
|
||||
td := htmlquery.FindOne(line, "//td")
|
||||
text := htmlquery.InnerText(td)
|
||||
text = strings.Replace(text, "\r", "", -1)
|
||||
text = strings.Replace(text, "\n", "", -1)
|
||||
text = strings.Replace(text, " ", "", -1)
|
||||
solutionVulnInfo.CVENumber = text
|
||||
}
|
||||
}
|
||||
if solutionVulnInfo.CVENumber == "" {
|
||||
solutionVulnInfo.CVENumber = "无cve编号"
|
||||
}
|
||||
}
|
||||
|
||||
func (RsasScanner RsasScanner) GenerateXlsx(output string) {
|
||||
filename := output + ".xlsx"
|
||||
|
||||
line := len(RsasScanner.AllVulnInfos)
|
||||
bar := progressbar.Default(int64(line))
|
||||
excel := excelize.NewFile()
|
||||
excel.NewSheet("主机漏洞清单")
|
||||
excel.SetSheetRow("主机漏洞清单", "A1", &[]string{"序号", "漏洞名称", "风险等级", "漏洞描述", "整改建议", "IP地址", "端口", "协议", "服务", "漏洞CVE编号", "版本"})
|
||||
|
||||
for i, infos := range RsasScanner.AllVulnInfos {
|
||||
bar.Add(1)
|
||||
axis := fmt.Sprintf("A%d", i+2)
|
||||
err := excel.SetSheetRow("主机漏洞清单", axis, &[]interface{}{
|
||||
i + 1,
|
||||
infos.VulnInfos,
|
||||
infos.RiskLevel,
|
||||
infos.Details,
|
||||
infos.Solution,
|
||||
infos.IpAddress,
|
||||
infos.Port,
|
||||
infos.Protocol,
|
||||
infos.Service,
|
||||
infos.CVENumber,
|
||||
infos.ServiceDetail,
|
||||
})
|
||||
if err != nil {
|
||||
println(err)
|
||||
}
|
||||
}
|
||||
|
||||
excel.DeleteSheet("Sheet1")
|
||||
|
||||
err := excel.SaveAs(filename)
|
||||
if err != nil {
|
||||
println(err.Error())
|
||||
} else {
|
||||
println("保存为:" + filename + ".xlsx")
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
////检查是否有漏报情况
|
||||
//func CheckVulnHasAssetInfo() {}
|
||||
//
|
||||
////根据基线规则匹配是否排除漏洞 true 为满足基线
|
||||
//func JudgeWithBaseLine(vulnWithAsset VulnInfoWithAssetInfo) (bool, string) {
|
||||
//
|
||||
// if JudgeNginx(vulnWithAsset) {
|
||||
// return true, "nginx版本为 " + vulnWithAsset.HtmlVulnInfo.ServiceDetail + " ,符合基线要求,暂不处理"
|
||||
// }
|
||||
// if JudgeTomcat(vulnWithAsset) {
|
||||
// return true, "tomcat版本为 " + vulnWithAsset.HtmlVulnInfo.ServiceDetail + " ,符合基线要求,暂不处理"
|
||||
// }
|
||||
// if JudgeSql(vulnWithAsset) {
|
||||
// return true, vulnWithAsset.HtmlVulnInfo.VulnInfos + " 为数据库漏洞,暂不处理"
|
||||
// }
|
||||
// if JudgeRedis(vulnWithAsset) {
|
||||
// return true, "redis版本为 " + vulnWithAsset.HtmlVulnInfo.ServiceDetail + " ,符合基线要求,暂不处理"
|
||||
// }
|
||||
// if JudgeRabbitMQ(vulnWithAsset) {
|
||||
// return true, "RabbitMQ版本为 " + vulnWithAsset.HtmlVulnInfo.ServiceDetail + " ,符合基线要求,暂不处理"
|
||||
// }
|
||||
// if JudgeOpenSSL(vulnWithAsset) {
|
||||
// return true, vulnWithAsset.HtmlVulnInfo.VulnInfos + " 为openssl漏洞,暂不处理"
|
||||
// }
|
||||
//
|
||||
|
||||
// if JudgeTls(vulnWithAsset) {
|
||||
// return true, vulnWithAsset.HtmlVulnInfo.VulnInfos + " 为ssl/tls漏洞,暂不处理"
|
||||
// }
|
||||
// return false, ""
|
||||
//}
|
||||
//
|
||||
////检查ng基线 true为符合基线
|
||||
//func JudgeNginx(vulnWithAsset VulnInfoWithAssetInfo) bool {
|
||||
// vulnBanner := strings.ToLower(vulnWithAsset.HtmlVulnInfo.ServiceDetail)
|
||||
// if strings.Contains(vulnBanner, "nginx/") {
|
||||
// ngBanner := strings.Replace(vulnBanner, "nginx/", "", 1)
|
||||
// ngbaseInt, err := strconv.Atoi(strings.Replace(nginxVersion, ".", "", -1))
|
||||
// if err != nil {
|
||||
// println("nginx基线常量有问题: " + nginxVersion)
|
||||
// return false
|
||||
// }
|
||||
// ngBannerInt, err := strconv.Atoi(strings.Replace(ngBanner, ".", "", -1))
|
||||
// if err != nil {
|
||||
// println("nginx版本获取有问题!漏洞名称:" + vulnWithAsset.HtmlVulnInfo.VulnInfos + " ip: " + vulnWithAsset.HtmlVulnInfo.IpAddress + "ng信息: " + vulnWithAsset.HtmlVulnInfo.ServiceDetail)
|
||||
// return false
|
||||
// }
|
||||
// ngBannerIntPrefix, err := strconv.Atoi(strings.Split(ngBanner, ".")[0] + strings.Split(ngBanner, ".")[1])
|
||||
// ngBaseIntPrefix, err := strconv.Atoi(strings.Split(nginxVersion, ".")[0] + strings.Split(nginxVersion, ".")[1])
|
||||
// if ngBannerInt >= ngbaseInt && ngBannerIntPrefix >= ngBaseIntPrefix {
|
||||
// return true
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// return false
|
||||
//}
|
||||
//
|
||||
//func JudgeTomcat(vulnWithAsset VulnInfoWithAssetInfo) bool {
|
||||
// vulnBanner := strings.ToLower(vulnWithAsset.HtmlVulnInfo.ServiceDetail)
|
||||
// if strings.Contains(vulnBanner, "tomcat/") {
|
||||
// tomcatBanner := strings.Replace(vulnBanner, "tomcat/", "", 1)
|
||||
// tomcatBanner = strings.Replace(tomcatBanner, ".tar", "", 1)
|
||||
// tomcatBanner = strings.Replace(tomcatBanner, " ", "", -1)
|
||||
// tomcatBaseInt, err := strconv.Atoi(strings.Replace(tomcatVersion, ".", "", -1))
|
||||
// if err != nil {
|
||||
// println("tomcat版本常量有问题: " + tomcatVersion)
|
||||
// return false
|
||||
// }
|
||||
// tomcatBannerInt, err := strconv.Atoi(strings.Replace(tomcatBanner, ".", "", -1))
|
||||
// if err != nil {
|
||||
// println("tomcat版本获取有问题!漏洞名称:" + vulnWithAsset.HtmlVulnInfo.VulnInfos + " ip: " + vulnWithAsset.HtmlVulnInfo.IpAddress + "ng信息: " + vulnWithAsset.HtmlVulnInfo.ServiceDetail)
|
||||
// return false
|
||||
// }
|
||||
// tomcatBannerIntPrefix, err := strconv.Atoi(strings.Split(tomcatBanner, ".")[0] + strings.Split(tomcatBanner, ".")[1])
|
||||
// tomcatBaseIntPrefix, err := strconv.Atoi(strings.Split(tomcatVersion, ".")[0] + strings.Split(tomcatVersion, ".")[1])
|
||||
// if tomcatBannerInt >= tomcatBaseInt && tomcatBannerIntPrefix >= tomcatBaseIntPrefix {
|
||||
// return true
|
||||
// }
|
||||
// }
|
||||
// return false
|
||||
//}
|
||||
//
|
||||
////数据库类型匹配到就不修复
|
||||
//func JudgeSql(vulnWithAsset VulnInfoWithAssetInfo) bool {
|
||||
// vulnBanner := strings.ToLower(vulnWithAsset.HtmlVulnInfo.ServiceDetail)
|
||||
// if strings.Contains(vulnBanner, "mysql/") {
|
||||
// return true
|
||||
// }
|
||||
// if strings.Contains(vulnBanner, "mariadb/") {
|
||||
// return true
|
||||
// }
|
||||
// if strings.Contains(vulnBanner, "mongodb/") {
|
||||
// return true
|
||||
// }
|
||||
//
|
||||
// return false
|
||||
//}
|
||||
//
|
||||
//func JudgeRedis(vulnWithAsset VulnInfoWithAssetInfo) bool {
|
||||
// vulnBanner := strings.ToLower(vulnWithAsset.HtmlVulnInfo.ServiceDetail)
|
||||
// if strings.Contains(vulnBanner, "redis/") {
|
||||
// redisBanner := strings.Replace(vulnBanner, "redis/", "", 1)
|
||||
// redisBaseInt, err := strconv.Atoi(strings.Replace(redisVersion, ".", "", -1))
|
||||
// if err != nil {
|
||||
// println("redis版本常量有问题: " + redisVersion)
|
||||
// return false
|
||||
// }
|
||||
// redisBannerInt, err := strconv.Atoi(strings.Replace(redisBanner, ".", "", -1))
|
||||
// if err != nil {
|
||||
// println("redis版本获取有问题!漏洞名称:" + vulnWithAsset.HtmlVulnInfo.VulnInfos + " ip: " + vulnWithAsset.HtmlVulnInfo.IpAddress + "ng信息: " + vulnWithAsset.HtmlVulnInfo.ServiceDetail)
|
||||
// return false
|
||||
// }
|
||||
// redisBannerIntPrefix, err := strconv.Atoi(strings.Split(redisBanner, ".")[0] + strings.Split(redisBanner, ".")[1])
|
||||
// redisBaseIntPrefix, err := strconv.Atoi(strings.Split(redisVersion, ".")[0] + strings.Split(redisVersion, ".")[1])
|
||||
// if redisBannerInt >= redisBaseInt && redisBannerIntPrefix >= redisBaseIntPrefix {
|
||||
// return true
|
||||
// }
|
||||
// }
|
||||
// return false
|
||||
//
|
||||
//}
|
||||
//
|
||||
//func JudgeRabbitMQ(vulnWithAsset VulnInfoWithAssetInfo) bool {
|
||||
// vulnBanner := strings.ToLower(vulnWithAsset.HtmlVulnInfo.ServiceDetail)
|
||||
// if strings.Contains(vulnBanner, "rabbitmq/") {
|
||||
// rabbitmqBanner := strings.Replace(vulnBanner, "rabbitmq/", "", 1)
|
||||
// rabbitmqBaseInt, err := strconv.Atoi(strings.Replace(RabbitMQ, ".", "", -1))
|
||||
// if err != nil {
|
||||
// println("RabbitMQ版本常量有问题: " + RabbitMQ)
|
||||
// return false
|
||||
// }
|
||||
// rabbitmqBannerInt, err := strconv.Atoi(strings.Replace(rabbitmqBanner, ".", "", -1))
|
||||
// if err != nil {
|
||||
// println("RabbitMQ版本获取有问题!漏洞名称:" + vulnWithAsset.HtmlVulnInfo.VulnInfos + " ip: " + vulnWithAsset.HtmlVulnInfo.IpAddress + "ng信息: " + vulnWithAsset.HtmlVulnInfo.ServiceDetail)
|
||||
// return false
|
||||
// }
|
||||
// rabbitmqBannerIntPrefix, err := strconv.Atoi(strings.Split(rabbitmqBanner, ".")[0] + strings.Split(rabbitmqBanner, ".")[1])
|
||||
// rabbitmqBaseIntPrefix, err := strconv.Atoi(strings.Split(RabbitMQ, ".")[0] + strings.Split(RabbitMQ, ".")[1])
|
||||
// if rabbitmqBannerInt >= rabbitmqBaseInt && rabbitmqBannerIntPrefix >= rabbitmqBaseIntPrefix {
|
||||
// return true
|
||||
// }
|
||||
// }
|
||||
// return false
|
||||
//
|
||||
//}
|
||||
//
|
||||
//func JudgeOpenSSL(vulnWithAsset VulnInfoWithAssetInfo) bool {
|
||||
// vulnBanner := strings.ToLower(vulnWithAsset.HtmlVulnInfo.ServiceDetail)
|
||||
// if strings.Contains(vulnBanner, "openssl/") && strings.Contains(strings.ToLower(vulnWithAsset.HtmlVulnInfo.VulnInfos), "openssl") {
|
||||
// return true
|
||||
// }
|
||||
// return false
|
||||
//}
|
||||
//
|
||||
//func JudgeTls(vulnWithAsset VulnInfoWithAssetInfo) bool {
|
||||
// vulnName := strings.ToLower(vulnWithAsset.HtmlVulnInfo.VulnInfos)
|
||||
// if strings.Contains(vulnName, "ssl/tls") || strings.Contains(vulnName, "tlsclient") {
|
||||
// return true
|
||||
// }
|
||||
// return false
|
||||
//}
|
||||
55
pkg/structs.go
Normal file
55
pkg/structs.go
Normal file
@@ -0,0 +1,55 @@
|
||||
package pkg
|
||||
|
||||
type RsasScanner struct {
|
||||
Account string
|
||||
Password string
|
||||
AllVulnInfos []HtmlVulnInfo
|
||||
//AssetInfos []AssetInfo
|
||||
//AssetExcel string
|
||||
//ZipResult string
|
||||
//VulnExcel string
|
||||
//OldVulnExcel string
|
||||
//OutputFileName string
|
||||
}
|
||||
|
||||
type HtmlAllVulnInfo struct {
|
||||
HtmlVulnInfos []HtmlVulnInfo
|
||||
}
|
||||
|
||||
type VulnInfoWithAssetInfo struct {
|
||||
HtmlVulnInfo HtmlVulnInfo
|
||||
//AssetInfos AssetInfo
|
||||
}
|
||||
|
||||
//type AssetInfo struct {
|
||||
// productLine string
|
||||
// DPlMNumber string
|
||||
// IpAddress string
|
||||
// Mail string
|
||||
// AppName string
|
||||
// ManagerName string
|
||||
// DevEnvironment string
|
||||
// Ascription string
|
||||
//}
|
||||
|
||||
type HtmlVulnInfo struct {
|
||||
IpAddress string
|
||||
Port string
|
||||
Protocol string
|
||||
Service string
|
||||
VulnInfos string
|
||||
RiskLevel string
|
||||
Details string
|
||||
Solution string
|
||||
CVENumber string
|
||||
ServiceDetail string
|
||||
Record string
|
||||
}
|
||||
|
||||
const nginxVersion = `1.18.0`
|
||||
const tomcatVersion = `9.0.40`
|
||||
const IIS = `10`
|
||||
const mysql = `5.7.31`
|
||||
const redisVersion = `6.0.8`
|
||||
const dotNet = `4.8`
|
||||
const RabbitMQ = `3.8.2`
|
||||
32
pkg/utils.go
Normal file
32
pkg/utils.go
Normal file
@@ -0,0 +1,32 @@
|
||||
package pkg
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func writeToExcel() {}
|
||||
|
||||
func CheckRegexString(regString string, htmlContent string) (finding string) {
|
||||
re := regexp.MustCompile(regString)
|
||||
finding = re.FindString(htmlContent)
|
||||
|
||||
return
|
||||
|
||||
}
|
||||
|
||||
func CheckColumnKey(columnName []string, m map[string]int, key string) string {
|
||||
if value, ok := m[key]; ok {
|
||||
//return utils.StringstripToSemicolon(columnName[value])
|
||||
return columnName[value]
|
||||
} else {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
func TrimString(s string) string {
|
||||
s = strings.Replace(s, "\r", "", -1)
|
||||
s = strings.Replace(s, "\n", "", -1)
|
||||
s = strings.Replace(s, " ", "", -1)
|
||||
return s
|
||||
}
|
||||
Reference in New Issue
Block a user