Files
vuls/report/json.go
2016-11-17 22:14:41 +09:00

151 lines
4.1 KiB
Go

/* Vuls - Vulnerability Scanner
Copyright (C) 2016 Future Architect, Inc. Japan.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package report
import (
"encoding/json"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"regexp"
"sort"
"strings"
"time"
c "github.com/future-architect/vuls/config"
"github.com/future-architect/vuls/models"
)
// JSONDirs array of json files path.
type JSONDirs []string
func (d JSONDirs) Len() int {
return len(d)
}
func (d JSONDirs) Swap(i, j int) {
d[i], d[j] = d[j], d[i]
}
func (d JSONDirs) Less(i, j int) bool {
return d[j] < d[i]
}
// JSONWriter writes results to file.
type JSONWriter struct {
ScannedAt time.Time
}
func (w JSONWriter) Write(scanResults []models.ScanResult) (err error) {
var path string
if path, err = ensureResultDir(w.ScannedAt); err != nil {
return fmt.Errorf("Failed to make direcotory/symlink : %s", err)
}
for _, scanResult := range scanResults {
scanResult.ScannedAt = w.ScannedAt
}
var jsonBytes []byte
for _, r := range scanResults {
jsonPath := ""
if len(r.Container.ContainerID) == 0 {
jsonPath = filepath.Join(path, fmt.Sprintf("%s.json", r.ServerName))
} else {
jsonPath = filepath.Join(path,
fmt.Sprintf("%s_%s.json", r.ServerName, r.Container.Name))
}
if jsonBytes, err = json.Marshal(r); err != nil {
return fmt.Errorf("Failed to Marshal to JSON: %s", err)
}
if err := ioutil.WriteFile(jsonPath, jsonBytes, 0600); err != nil {
return fmt.Errorf("Failed to write JSON. path: %s, err: %s", jsonPath, err)
}
}
return nil
}
// JSONDirPattern is file name pattern of JSON directory
var JSONDirPattern = regexp.MustCompile(`^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}[+-]\d{2}:\d{2}$`)
// GetValidJSONDirs return valid json directory as array
func GetValidJSONDirs() (jsonDirs JSONDirs, err error) {
var dirInfo []os.FileInfo
if dirInfo, err = ioutil.ReadDir(c.Conf.ResultsDir); err != nil {
err = fmt.Errorf("Failed to read %s: %s", c.Conf.ResultsDir, err)
return
}
for _, d := range dirInfo {
if d.IsDir() && JSONDirPattern.MatchString(d.Name()) {
jsonDir := filepath.Join(c.Conf.ResultsDir, d.Name())
jsonDirs = append(jsonDirs, jsonDir)
}
}
sort.Sort(jsonDirs)
return
}
// LoadOneScanHistory read JSON data
func LoadOneScanHistory(jsonDir string) (scanHistory models.ScanHistory, err error) {
var scanResults []models.ScanResult
var files []os.FileInfo
if files, err = ioutil.ReadDir(jsonDir); err != nil {
err = fmt.Errorf("Failed to read %s: %s", jsonDir, err)
return
}
for _, file := range files {
if filepath.Ext(file.Name()) != ".json" {
continue
}
var scanResult models.ScanResult
var data []byte
jsonPath := filepath.Join(jsonDir, file.Name())
if data, err = ioutil.ReadFile(jsonPath); err != nil {
err = fmt.Errorf("Failed to read %s: %s", jsonPath, err)
return
}
if json.Unmarshal(data, &scanResult) != nil {
err = fmt.Errorf("Failed to parse %s: %s", jsonPath, err)
return
}
scanResults = append(scanResults, scanResult)
}
if len(scanResults) == 0 {
err = fmt.Errorf("There is no json file under %s", jsonDir)
return
}
var scannedAt time.Time
if scanResults[0].ScannedAt.IsZero() {
splitPath := strings.Split(jsonDir, string(os.PathSeparator))
timeStr := splitPath[len(splitPath)-1]
if scannedAt, err = time.Parse(time.RFC3339, timeStr); err != nil {
err = fmt.Errorf("Failed to parse %s: %s", timeStr, err)
return
}
} else {
scannedAt = scanResults[0].ScannedAt
}
scanHistory = models.ScanHistory{
ScanResults: scanResults,
ScannedAt: scannedAt,
}
return
}