mirror of
https://github.com/gocsaf/csaf.git
synced 2025-12-22 11:55:40 +01:00
Write a first version of the ROLIE feed.
This commit is contained in:
parent
b8d51da4cb
commit
1d0d8a6d03
3 changed files with 136 additions and 5 deletions
|
|
@ -227,8 +227,84 @@ func (c *controller) upload(rw http.ResponseWriter, r *http.Request) {
|
||||||
c.cfg, t,
|
c.cfg, t,
|
||||||
func(folder string, pmd *csaf.ProviderMetadata) error {
|
func(folder string, pmd *csaf.ProviderMetadata) error {
|
||||||
|
|
||||||
|
// Load the feed
|
||||||
|
ts := string(t)
|
||||||
|
feedName := "csaf-feed-tlp-" + ts + ".json"
|
||||||
|
|
||||||
|
feed := filepath.Join(folder, feedName)
|
||||||
|
var rolie *csaf.ROLIEFeed
|
||||||
|
if err := func() error {
|
||||||
|
f, err := os.Open(feed)
|
||||||
|
if err != nil {
|
||||||
|
if os.IsNotExist(err) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
rolie, err = csaf.LoadROLIEFeed(f)
|
||||||
|
return err
|
||||||
|
}(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create new if does not exists.
|
||||||
|
if rolie == nil {
|
||||||
|
feedURL := c.cfg.Domain +
|
||||||
|
"/.well-known/csaf/" + ts + "/" + feedName
|
||||||
|
rolie = &csaf.ROLIEFeed{
|
||||||
|
ID: "csaf-feed-tlp-" + ts,
|
||||||
|
Title: "CSAF feed (TLP:" + strings.ToUpper(ts) + ")",
|
||||||
|
Link: []csaf.Link{{
|
||||||
|
Rel: "rel",
|
||||||
|
HRef: feedURL,
|
||||||
|
}},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rolie.Updated = csaf.TimeStamp(time.Now())
|
||||||
|
|
||||||
year := strconv.Itoa(ex.currentReleaseDate.Year())
|
year := strconv.Itoa(ex.currentReleaseDate.Year())
|
||||||
|
|
||||||
|
csafURL := c.cfg.Domain +
|
||||||
|
"/.well-known/csaf/" + ts + "/" + year + "/" + newCSAF
|
||||||
|
|
||||||
|
e := rolie.EntryByID(ex.id)
|
||||||
|
if e == nil {
|
||||||
|
e = &csaf.Entry{ID: ex.id}
|
||||||
|
rolie.Entry = append(rolie.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,
|
||||||
|
}}
|
||||||
|
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 := saveToFile(feed, rolie); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create yearly subfolder
|
||||||
|
|
||||||
subDir := filepath.Join(folder, year)
|
subDir := filepath.Join(folder, year)
|
||||||
|
|
||||||
// Create folder if it does not exists.
|
// Create folder if it does not exists.
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ func createSecurity(c *config) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
fmt.Fprintf(
|
fmt.Fprintf(
|
||||||
f, "CSAF: https://%s/.wellknown/csaf/provider-metadata.json\n",
|
f, "CSAF: %s/.well-known/csaf/provider-metadata.json\n",
|
||||||
c.Domain)
|
c.Domain)
|
||||||
return f.Close()
|
return f.Close()
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -214,3 +214,20 @@ func writeHashedFile(fname, name string, data []byte, armored string) error {
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type saver interface {
|
||||||
|
Save(io.Writer) error
|
||||||
|
}
|
||||||
|
|
||||||
|
func saveToFile(fname string, s saver) error {
|
||||||
|
f, err1 := os.Create(fname)
|
||||||
|
if err1 != nil {
|
||||||
|
return err1
|
||||||
|
}
|
||||||
|
err1 = s.Save(f)
|
||||||
|
err2 := f.Close()
|
||||||
|
if err1 != nil {
|
||||||
|
return err1
|
||||||
|
}
|
||||||
|
return err2
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,12 @@
|
||||||
package csaf
|
package csaf
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"io"
|
||||||
|
"sort"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
type Link struct {
|
type Link struct {
|
||||||
Rel string `json:"rel"`
|
Rel string `json:"rel"`
|
||||||
HRef string `json:"href"`
|
HRef string `json:"href"`
|
||||||
|
|
@ -30,7 +37,7 @@ type Entry struct {
|
||||||
Link []Link `json:"link"`
|
Link []Link `json:"link"`
|
||||||
Published TimeStamp `json:"published"`
|
Published TimeStamp `json:"published"`
|
||||||
Updated TimeStamp `json:"updated"`
|
Updated TimeStamp `json:"updated"`
|
||||||
Summary Summary `json:"summary"`
|
Summary *Summary `json:"summary,omitempty"`
|
||||||
Content Content `json:"content"`
|
Content Content `json:"content"`
|
||||||
Format Format `json:"format"`
|
Format Format `json:"format"`
|
||||||
}
|
}
|
||||||
|
|
@ -38,8 +45,39 @@ type Entry struct {
|
||||||
type ROLIEFeed struct {
|
type ROLIEFeed struct {
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
Title string `json:"title"`
|
Title string `json:"title"`
|
||||||
Link []Link `json:"link"`
|
Link []Link `json:"link,omitempty"`
|
||||||
Category []Category `json:"category"`
|
Category []Category `json:"category,omitempty"`
|
||||||
Updated TimeStamp `json:"updated"`
|
Updated TimeStamp `json:"updated"`
|
||||||
Entry []*Entry `json:"entry"`
|
Entry []*Entry `json:"entry,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func LoadROLIEFeed(r io.Reader) (*ROLIEFeed, error) {
|
||||||
|
dec := json.NewDecoder(r)
|
||||||
|
var rf ROLIEFeed
|
||||||
|
if err := dec.Decode(&rf); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &rf, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rf *ROLIEFeed) Save(w io.Writer) error {
|
||||||
|
enc := json.NewEncoder(w)
|
||||||
|
enc.SetIndent("", " ")
|
||||||
|
return enc.Encode(rf)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rf *ROLIEFeed) EntryByID(id string) *Entry {
|
||||||
|
for _, entry := range rf.Entry {
|
||||||
|
if entry.ID == id {
|
||||||
|
return entry
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rf *ROLIEFeed) SortEntriesByUpdated() {
|
||||||
|
entries := rf.Entry
|
||||||
|
sort.Slice(entries, func(i, j int) bool {
|
||||||
|
return time.Time(entries[j].Updated).Before(time.Time(entries[i].Updated))
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue