diff --git a/cmd/csaf_provider/actions.go b/cmd/csaf_provider/actions.go index 37428c8..ec621c0 100644 --- a/cmd/csaf_provider/actions.go +++ b/cmd/csaf_provider/actions.go @@ -143,20 +143,6 @@ func (c *controller) create(*http.Request) (interface{}, error) { }, nil } -// loadROLIEFeed loads a ROLIE feed from file if its exists. -// Returns nil if the file does not exists. -func loadROLIEFeed(feed string) (*csaf.ROLIEFeed, error) { - f, err := os.Open(feed) - if err != nil { - if os.IsNotExist(err) { - return nil, nil - } - return nil, err - } - defer f.Close() - return csaf.LoadROLIEFeed(f) -} - func (c *controller) upload(r *http.Request) (interface{}, error) { newCSAF, data, err := c.loadCSAF(r) @@ -226,85 +212,13 @@ func (c *controller) upload(r *http.Request) (interface{}, error) { c.cfg, t, func(folder string, pmd *csaf.ProviderMetadata) error { - // Load the feed - ts := string(t) - feedName := "csaf-feed-tlp-" + ts + ".json" - - feed := filepath.Join(folder, feedName) - rolie, err := loadROLIEFeed(feed) - if err != nil { - return err - } - - feedURL := csaf.JSONURL( - c.cfg.CanonicalURLPrefix + - "/.well-known/csaf/" + ts + "/" + feedName) - - tlpLabel := csaf.TLPLabel(strings.ToUpper(ts)) - - // Create new if does not exists. - if rolie == nil { - rolie = &csaf.ROLIEFeed{ - Feed: csaf.FeedData{ - ID: "csaf-feed-tlp-" + ts, - Title: "CSAF feed (TLP:" + string(tlpLabel) + ")", - Link: []csaf.Link{{ - Rel: "self", - HRef: string(feedURL), - }}, - Category: []csaf.ROLIECategory{{ - Scheme: "urn:ietf:params:rolie:category:information-type", - Term: "csaf", - }}, - }, - } - } - - rolie.Feed.Updated = csaf.TimeStamp(time.Now().UTC()) - - year := strconv.Itoa(ex.InitialReleaseDate.Year()) - - csafURL := c.cfg.CanonicalURLPrefix + - "/.well-known/csaf/" + ts + "/" + year + "/" + newCSAF - - e := rolie.EntryByID(ex.ID) - if e == nil { - e = &csaf.Entry{ID: ex.ID} - rolie.Feed.Entry = append(rolie.Feed.Entry, e) - } - - e.Titel = ex.Title - e.Published = csaf.TimeStamp(ex.InitialReleaseDate) - e.Updated = csaf.TimeStamp(ex.CurrentReleaseDate) - e.Link = []csaf.Link{ - {Rel: "self", HRef: csafURL}, - {Rel: "hash", HRef: csafURL + ".sha256"}, - {Rel: "hash", HRef: csafURL + ".sha512"}, - {Rel: "signature", HRef: csafURL + ".asc"}, - } - e.Format = csaf.Format{ - Schema: "https://docs.oasis-open.org/csaf/csaf/v2.0/csaf_json_schema.json", - Version: "2.0", - } - e.Content = csaf.Content{ - Type: "application/json", - Src: csafURL, - } - if ex.Summary != "" { - e.Summary = &csaf.Summary{Content: ex.Summary} - } else { - e.Summary = nil - } - - // Sort by descending updated order. - rolie.SortEntriesByUpdated() - - // Store the feed - if err := util.WriteToFile(feed, rolie); err != nil { + // extend the ROLIE feed. + if err := c.extendROLIE(folder, newCSAF, t, ex); err != nil { return err } // Create yearly subfolder + year := strconv.Itoa(ex.InitialReleaseDate.Year()) subDir := filepath.Join(folder, year) diff --git a/cmd/csaf_provider/rolie.go b/cmd/csaf_provider/rolie.go new file mode 100644 index 0000000..ae940e4 --- /dev/null +++ b/cmd/csaf_provider/rolie.go @@ -0,0 +1,117 @@ +// This file is Free Software under the MIT License +// without warranty, see README.md and LICENSES/MIT.txt for details. +// +// SPDX-License-Identifier: MIT +// +// SPDX-FileCopyrightText: 2021 German Federal Office for Information Security (BSI) +// Software-Engineering: 2021 Intevation GmbH + +package main + +import ( + "os" + "path/filepath" + "strconv" + "strings" + "time" + + "github.com/csaf-poc/csaf_distribution/csaf" + "github.com/csaf-poc/csaf_distribution/util" +) + +func (c *controller) extendROLIE( + folder string, + newCSAF string, + t tlp, + ex *csaf.AdvisorySummary, +) error { + // Load the feed + ts := string(t) + feedName := "csaf-feed-tlp-" + ts + ".json" + + feed := filepath.Join(folder, feedName) + rolie, err := loadROLIEFeed(feed) + if err != nil { + return err + } + + feedURL := csaf.JSONURL( + c.cfg.CanonicalURLPrefix + + "/.well-known/csaf/" + ts + "/" + feedName) + + tlpLabel := csaf.TLPLabel(strings.ToUpper(ts)) + + // Create new if does not exists. + if rolie == nil { + rolie = &csaf.ROLIEFeed{ + Feed: csaf.FeedData{ + ID: "csaf-feed-tlp-" + ts, + Title: "CSAF feed (TLP:" + string(tlpLabel) + ")", + Link: []csaf.Link{{ + Rel: "self", + HRef: string(feedURL), + }}, + Category: []csaf.ROLIECategory{{ + Scheme: "urn:ietf:params:rolie:category:information-type", + Term: "csaf", + }}, + }, + } + } + + rolie.Feed.Updated = csaf.TimeStamp(time.Now().UTC()) + + year := strconv.Itoa(ex.InitialReleaseDate.Year()) + + csafURL := c.cfg.CanonicalURLPrefix + + "/.well-known/csaf/" + ts + "/" + year + "/" + newCSAF + + e := rolie.EntryByID(ex.ID) + if e == nil { + e = &csaf.Entry{ID: ex.ID} + rolie.Feed.Entry = append(rolie.Feed.Entry, e) + } + + e.Titel = ex.Title + e.Published = csaf.TimeStamp(ex.InitialReleaseDate) + e.Updated = csaf.TimeStamp(ex.CurrentReleaseDate) + e.Link = []csaf.Link{ + {Rel: "self", HRef: csafURL}, + {Rel: "hash", HRef: csafURL + ".sha256"}, + {Rel: "hash", HRef: csafURL + ".sha512"}, + {Rel: "signature", HRef: csafURL + ".asc"}, + } + e.Format = csaf.Format{ + Schema: "https://docs.oasis-open.org/csaf/csaf/v2.0/csaf_json_schema.json", + Version: "2.0", + } + e.Content = csaf.Content{ + Type: "application/json", + Src: csafURL, + } + if ex.Summary != "" { + e.Summary = &csaf.Summary{Content: ex.Summary} + } else { + e.Summary = nil + } + + // Sort by descending updated order. + rolie.SortEntriesByUpdated() + + // Store the feed + return util.WriteToFile(feed, rolie) +} + +// loadROLIEFeed loads a ROLIE feed from file if its exists. +// Returns nil if the file does not exists. +func loadROLIEFeed(feed string) (*csaf.ROLIEFeed, error) { + f, err := os.Open(feed) + if err != nil { + if os.IsNotExist(err) { + return nil, nil + } + return nil, err + } + defer f.Close() + return csaf.LoadROLIEFeed(f) +}