vuln-list-update/cwe/cwe.go
Simarpreet Singh 319f079602
cwe: Add initial logic to download and save CWE files (#40)
* cwe: Add initial logic to download and save CWE files

Signed-off-by: Simarpreet Singh <simar@linux.com>

* cwe: Add logic to parse and save XML data as file

Signed-off-by: Simarpreet Singh <simar@linux.com>

* cwe: Dont save XML file as output

Signed-off-by: Simarpreet Singh <simar@linux.com>

* cwe: Save each CWE-ID as a JSON document

Signed-off-by: Simarpreet Singh <simar@linux.com>

* cwe: Address nits

Signed-off-by: Simarpreet Singh <simar@linux.com>
2020-08-04 14:01:18 -07:00

116 lines
2.4 KiB
Go

package cwe
import (
"archive/zip"
"bytes"
"encoding/json"
"encoding/xml"
"fmt"
"io/ioutil"
"log"
"os"
"path/filepath"
"github.com/aquasecurity/vuln-list-update/utils"
"golang.org/x/xerrors"
)
type CWEConfig struct {
url string
retryTimes int
cweDir string
}
const (
cweURL = "https://cwe.mitre.org/data/xml/cwec_latest.xml.zip"
)
func NewCWEConfig() CWEConfig {
return NewCWEWithConfig(cweURL, filepath.Join(utils.VulnListDir(), "cwe"), 5)
}
func NewCWEWithConfig(url, path string, retryTimes int) CWEConfig {
return CWEConfig{
url: url,
retryTimes: retryTimes,
cweDir: path,
}
}
func (c CWEConfig) Update() error {
log.Println("Fetching CWE data...")
data, err := utils.FetchURL(c.url, "", c.retryTimes)
if err != nil {
return xerrors.Errorf("failed to fetch cwe data: %w", err)
}
b, err := c.unzip(data)
if err != nil {
return err
}
var wc WeaknessCatalog
if wc, err = xmlToJSON(b); err != nil {
return err
}
if err := os.MkdirAll(c.cweDir, os.ModePerm); err != nil {
return xerrors.Errorf("unable to create cwe directory: %w", err)
}
for _, w := range wc.Weaknesses.Weakness {
b, err := json.MarshalIndent(w, "", " ")
if err != nil {
log.Printf("unable to marshal: %d, err: %s\n", w.ID, err)
continue
}
if err := c.saveFile(b, fmt.Sprintf("CWE-%d.json", w.ID)); err != nil {
return err
}
}
return nil
}
func (c CWEConfig) saveFile(b []byte, fileType string) error {
if err := ioutil.WriteFile(filepath.Join(c.cweDir, fileType), b, 0600); err != nil {
return xerrors.Errorf("failed to write %s file: %w", fileType, err)
}
return nil
}
func (c CWEConfig) unzip(data []byte) ([]byte, error) {
zipReader, err := zip.NewReader(bytes.NewReader(data), int64(len(data)))
if err != nil {
return nil, xerrors.Errorf("unable to initialize zip: %w", err)
}
if len(zipReader.File) > 1 {
return nil, xerrors.Errorf("invalid CWE zip: too many files in archive")
}
b, err := readZipFile(zipReader.File[0])
if err != nil {
return nil, xerrors.Errorf("unable to read zip archive: %w", err)
}
return b, nil
}
func readZipFile(zf *zip.File) ([]byte, error) {
f, err := zf.Open()
if err != nil {
return nil, err
}
defer f.Close()
return ioutil.ReadAll(f)
}
func xmlToJSON(b []byte) (WeaknessCatalog, error) {
var wc WeaknessCatalog
if err := xml.Unmarshal(b, &wc); err != nil {
return WeaknessCatalog{}, err
}
return wc, nil
}