From d94b83df0de95db7ae63726fd11ddd30dff72f39 Mon Sep 17 00:00:00 2001 From: Paul Duncan Date: Sat, 19 Mar 2022 03:50:06 -0400 Subject: cmd: working update cmd --- cmd/cmd.go | 105 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ cmd/update.go | 62 +++++++++++++++++++++++++++++++++- 2 files changed, 166 insertions(+), 1 deletion(-) (limited to 'cmd') diff --git a/cmd/cmd.go b/cmd/cmd.go index 1619a71..fd195aa 100644 --- a/cmd/cmd.go +++ b/cmd/cmd.go @@ -2,12 +2,18 @@ package cmd import ( + "compress/gzip" "encoding/json" + "encoding/xml" + "github.com/pablotron/cvez/cisa" + "github.com/pablotron/cvez/cpedict" + "github.com/pablotron/cvez/cpematch" "github.com/pablotron/cvez/datadir" "github.com/pablotron/cvez/dbstore" "github.com/pablotron/cvez/nvdmirror" "github.com/rs/zerolog" "github.com/rs/zerolog/log" + nvd_feed "github.com/pablotron/cvez/feed" "os" "path/filepath" "strings" @@ -87,3 +93,102 @@ func init() { rootCmd.AddCommand(cvssCmd) rootCmd.AddCommand(updateCmd) } + +// read gzipped file, pass reader to callback. +func gzOpen(path string, fn func(*gzip.Reader)) { + f, err := os.Open(path) + if err != nil { + log.Error().Err(err).Msg("Open") + os.Exit(-1) + } + defer f.Close() + + // create gzip reader + r, err := gzip.NewReader(f) + if err != nil { + log.Error().Err(err).Msg("NewReader") + os.Exit(-1) + } + + fn(r) +} + +// read gzipped json, pass decoder to callback +func jsonGzOpen(path string, fn func(*json.Decoder)) { + gzOpen(path, func(r *gzip.Reader) { + fn(json.NewDecoder(r)) + }) +} + +// read gzipped xml, pass decoder to callback +func xmlGzOpen(path string, fn func(*xml.Decoder)) { + gzOpen(path, func(r *gzip.Reader) { + fn(xml.NewDecoder(r)) + }) +} + +// Read feed from file. +func getFeed(path string) nvd_feed.Feed { + var feed nvd_feed.Feed + + jsonGzOpen(path, func(d *json.Decoder) { + if err := d.Decode(&feed); err != nil { + log.Error().Err(err).Msg("Decode") + os.Exit(-1) + } + }) + + // return feed + return feed +} + +// Read cpe matches from file. +func getCpeMatches(path string) cpematch.Matches { + var matches cpematch.Matches + + jsonGzOpen(path, func(d *json.Decoder) { + if err := d.Decode(&matches); err != nil { + log.Error().Err(err).Msg("Decode") + os.Exit(-1) + } + }) + + // return matches + return matches +} + +// Read cpe dictionary from file. +func getCpeDict(path string) cpedict.Dictionary { + var dict cpedict.Dictionary + + xmlGzOpen(path, func(d *xml.Decoder) { + if err := d.Decode(&dict); err != nil { + log.Error().Err(err).Msg("Decode") + os.Exit(-1) + } + }) + + // return dictionary + return dict +} + +// Read cisa catalog from file. +func getCisaCatalog(path string) cisa.Catalog { + f, err := os.Open(path) + if err != nil { + log.Error().Err(err).Msg("Open") + os.Exit(-1) + } + defer f.Close() + + // create decoder, decode catalog + var cat cisa.Catalog + d := json.NewDecoder(f) + if err = d.Decode(&cat); err != nil { + log.Error().Err(err).Msg("Decode") + os.Exit(-1) + } + + // return catalog + return cat +} diff --git a/cmd/update.go b/cmd/update.go index b6f2882..86e6c7a 100644 --- a/cmd/update.go +++ b/cmd/update.go @@ -2,8 +2,14 @@ package cmd import ( // "encoding/json" + "context" + "github.com/pablotron/cvez/cisa" "github.com/pablotron/cvez/nvdmirror" + "github.com/rs/zerolog/log" "github.com/spf13/cobra" + nvd_feed "github.com/pablotron/cvez/feed" + "os" + "path/filepath" ) var updateCmd = &cobra.Command{ @@ -28,6 +34,60 @@ var updateCmd = &cobra.Command{ // sync data, get updates updates := nvdmirror.Sync(config, &cache, cacheDir) - jsonEncode(updates) + if len(updates) > 0 { + // connect to db + ctx := context.Background() + db := getDb() + + // build list of feeds to add + log.Info().Msg("load feeds") + var feeds []nvd_feed.Feed + for _, row := range(updates) { + if row.Type == nvdmirror.UpdateCveYear { + feeds = append(feeds, getFeed(filepath.Join(cacheDir, row.Path))) + } + } + + if len(feeds) > 0 { + log.Info().Msg("AddCveFeeds") + if _, err := db.AddCveFeeds(ctx, feeds); err != nil { + // FIXME: failing like this leaves an invalid cache + log.Error().Err(err).Msg("AddCveFeeds") + os.Exit(-1) + } + } + + // process cpe dictionary before cpe matches to prevent FK + // constraint violations + for _, row := range(updates) { + if row.Type == nvdmirror.UpdateCpeDict { + log.Info().Msg("AddCpeDictionary") + dict := getCpeDict(filepath.Join(cacheDir, row.Path)) + if err := db.AddCpeDictionary(ctx, dict); err != nil { + log.Error().Err(err).Msg("AddCpeDictionary") + os.Exit(-1) + } + } + } + + for _, row := range(updates) { + switch row.Type { + case nvdmirror.UpdateCpeMatch: + log.Info().Msg("AddCpeMatches") + matches := getCpeMatches(filepath.Join(cacheDir, row.Path)) + if err := db.AddCpeMatches(ctx, matches); err != nil { + log.Error().Err(err).Msg("AddCpeMatches") + os.Exit(-1) + } + case nvdmirror.UpdateCisaKevc: + log.Info().Msg("AddCisaCatalogs") + cat := getCisaCatalog(filepath.Join(cacheDir, row.Path)) + if _, err := db.AddCisaCatalogs(ctx, []cisa.Catalog { cat }); err != nil { + log.Error().Err(err).Msg("AddCisaCatalogs") + os.Exit(-1) + } + } + } + } }, } -- cgit v1.2.3