1
0
Fork 0
mirror of https://github.com/gocsaf/csaf.git synced 2025-12-22 11:55:40 +01:00

Fix golint warnings.

This commit is contained in:
Sascha L. Teichmann 2021-11-25 18:21:23 +01:00
parent 6b05323271
commit 04fb8f7e75
6 changed files with 122 additions and 49 deletions

View file

@ -248,7 +248,7 @@ func (c *controller) upload(rw http.ResponseWriter, r *http.Request) {
return err return err
} }
feedURL := csaf.JsonURL( feedURL := csaf.JSONURL(
c.cfg.Domain + "/.well-known/csaf/" + ts + "/" + feedName) c.cfg.Domain + "/.well-known/csaf/" + ts + "/" + feedName)
tlpLabel := csaf.TLPLabel(strings.ToUpper(ts)) tlpLabel := csaf.TLPLabel(strings.ToUpper(ts))

View file

@ -26,7 +26,7 @@ const (
type extraction struct { type extraction struct {
id string id string
title string title string
publisher *csaf.CSAFPublisher publisher *csaf.Publisher
initialReleaseDate time.Time initialReleaseDate time.Time
currentReleaseDate time.Time currentReleaseDate time.Time
summary string summary string
@ -109,7 +109,7 @@ func (e *extraction) extractPublisher(path extractFunc) error {
if err := enc.Encode(p); err != nil { if err := enc.Encode(p); err != nil {
return err return err
} }
e.publisher = new(csaf.CSAFPublisher) e.publisher = new(csaf.Publisher)
if err := json.Unmarshal(buf.Bytes(), e.publisher); err != nil { if err := json.Unmarshal(buf.Bytes(), e.publisher); err != nil {
return err return err
} }

View file

@ -42,9 +42,8 @@ func createSecurity(c *config) error {
f, "CSAF: %s/.well-known/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 {
return err
} }
return err
} }
return nil return nil
} }

View file

@ -24,7 +24,7 @@ func newProviderMetadata(cfg *config) *csaf.ProviderMetadata {
var ( var (
ts = string(t) ts = string(t)
feedName = "csaf-feed-tlp-" + ts + ".json" feedName = "csaf-feed-tlp-" + ts + ".json"
feedURL = csaf.JsonURL( feedURL = csaf.JSONURL(
cfg.Domain + "/.well-known/csaf/" + ts + "/" + feedName) cfg.Domain + "/.well-known/csaf/" + ts + "/" + feedName)
tlpLabel = csaf.TLPLabel(strings.ToUpper(ts)) tlpLabel = csaf.TLPLabel(strings.ToUpper(ts))
) )

View file

@ -10,14 +10,20 @@ import (
"time" "time"
) )
// TLPLabel is the traffic light policy of the CSAF.
type TLPLabel string type TLPLabel string
const ( const (
// TLPLabelUnlabeled is the 'UNLABELED' policy.
TLPLabelUnlabeled = "UNLABELED" TLPLabelUnlabeled = "UNLABELED"
TLPLabelWhite = "WHITE" // TLPLabelWhite is the 'WHITE' policy.
TLPLabelGreen = "GREEN" TLPLabelWhite = "WHITE"
TLPLabelAmber = "AMBER" // TLPLabelGreen is the 'GREEN' policy.
TLPLabelRed = "RED" TLPLabelGreen = "GREEN"
// TLPLabelAmber is the 'AMBER' policy.
TLPLabelAmber = "AMBER"
// TLPLabelRed is the 'RED' policy.
TLPLabelRed = "RED"
) )
var tlpLabelPattern = alternativesUnmarshal( var tlpLabelPattern = alternativesUnmarshal(
@ -27,47 +33,63 @@ var tlpLabelPattern = alternativesUnmarshal(
string("AMBER"), string("AMBER"),
string("RED")) string("RED"))
type JsonURL string // JSONURL is an URL to JSON document.
type JSONURL string
var jsonURLPattern = patternUnmarshal(`\.json$`) var jsonURLPattern = patternUnmarshal(`\.json$`)
// Feed is CSAF feed.
type Feed struct { type Feed struct {
Summary string `json:"summary"` Summary string `json:"summary"`
TLPLabel *TLPLabel `json:"tlp_label"` // required TLPLabel *TLPLabel `json:"tlp_label"` // required
URL *JsonURL `json:"url"` // required URL *JSONURL `json:"url"` // required
} }
// ROLIE is the ROLIE extension of the CSAF feed.
type ROLIE struct { type ROLIE struct {
Categories []JsonURL `json:"categories,omitempty"` Categories []JSONURL `json:"categories,omitempty"`
Feeds []Feed `json:"feeds"` // required Feeds []Feed `json:"feeds"` // required
Services []JsonURL `json:"services,omitempty"` Services []JSONURL `json:"services,omitempty"`
} }
// Distribution is a distribution of a CSAF feed.
type Distribution struct { type Distribution struct {
DirectoryURL string `json:"directory_url,omitempty"` DirectoryURL string `json:"directory_url,omitempty"`
Rolie []ROLIE `json:"rolie"` Rolie []ROLIE `json:"rolie"`
} }
// TimeStamp represents a time stamp in a CSAF feed.
type TimeStamp time.Time type TimeStamp time.Time
// Fingerprint is the fingerprint of a OpenPGP key used to sign
// the CASF documents.
type Fingerprint string type Fingerprint string
var fingerprintPattern = patternUnmarshal(`^[0-9a-fA-F]{40,}$`) var fingerprintPattern = patternUnmarshal(`^[0-9a-fA-F]{40,}$`)
// PGPKey is location and the fingerprint of the key
// used to sign the CASF documents.
type PGPKey struct { type PGPKey struct {
Fingerprint Fingerprint `json:"fingerprint,omitempty"` Fingerprint Fingerprint `json:"fingerprint,omitempty"`
URL *string `json:"url"` // required URL *string `json:"url"` // required
} }
type CSAFCategory string // Category is the category of the CSAF feed.
type Category string
const ( const (
CSAFCategoryCoordinator CSAFCategory = "coordinator" // CSAFCategoryCoordinator is the "coordinator" category.
CSAFCategoryDiscoverer CSAFCategory = "discoverer" CSAFCategoryCoordinator Category = "coordinator"
CSAFCategoryOther CSAFCategory = "other" // CSAFCategoryDiscoverer is the "discoverer" category.
CSAFCategoryTranslator CSAFCategory = "translator" CSAFCategoryDiscoverer Category = "discoverer"
CSAFCategoryUser CSAFCategory = "user" // CSAFCategoryOther is the "other" category.
CSAFCategoryVendor CSAFCategory = "vendor" CSAFCategoryOther Category = "other"
// CSAFCategoryTranslator is the "translator" category.
CSAFCategoryTranslator Category = "translator"
// CSAFCategoryUser is the "user" category.
CSAFCategoryUser Category = "user"
// CSAFCategoryVendor is the "vendor" category.
CSAFCategoryVendor Category = "vendor"
) )
var csafCategoryPattern = alternativesUnmarshal( var csafCategoryPattern = alternativesUnmarshal(
@ -78,25 +100,32 @@ var csafCategoryPattern = alternativesUnmarshal(
string(CSAFCategoryUser), string(CSAFCategoryUser),
string(CSAFCategoryVendor)) string(CSAFCategoryVendor))
type CSAFPublisher struct { // Publisher is the publisher of the feed.
Category *CSAFCategory `json:"category"` // required type Publisher struct {
Name *string `json:"name"` // required Category *Category `json:"category"` // required
Namespace *string `json:"namespace"` // required Name *string `json:"name"` // required
ContactDetails string `json:"contact_details,omitempty"` Namespace *string `json:"namespace"` // required
IssuingAuthority string `json:"issuing_authority,omitempty"` ContactDetails string `json:"contact_details,omitempty"`
IssuingAuthority string `json:"issuing_authority,omitempty"`
} }
// MetadataVersion is the metadata version of the feed.
type MetadataVersion string type MetadataVersion string
// MetadataVersion20 is the current version of the schema.
const MetadataVersion20 MetadataVersion = "2.0" const MetadataVersion20 MetadataVersion = "2.0"
var metadataVersionPattern = alternativesUnmarshal(string(MetadataVersion20)) var metadataVersionPattern = alternativesUnmarshal(string(MetadataVersion20))
// MetadataRole is the role of the feed.
type MetadataRole string type MetadataRole string
const ( const (
MetadataRolePublisher MetadataRole = "csaf_publisher" // MetadataRolePublisher is the "csaf_publisher" role.
MetadataRoleProvider MetadataRole = "csaf_provider" MetadataRolePublisher MetadataRole = "csaf_publisher"
// MetadataRoleProvider is the "csaf_provider" role.
MetadataRoleProvider MetadataRole = "csaf_provider"
// MetadataRoleTrustedProvider is the "csaf_trusted_provider" role.
MetadataRoleTrustedProvider MetadataRole = "csaf_trusted_provider" MetadataRoleTrustedProvider MetadataRole = "csaf_trusted_provider"
) )
@ -105,10 +134,12 @@ var metadataRolePattern = alternativesUnmarshal(
string(MetadataRoleProvider), string(MetadataRoleProvider),
string(MetadataRoleTrustedProvider)) string(MetadataRoleTrustedProvider))
// ProviderURL is the URL of the provider document.
type ProviderURL string type ProviderURL string
var providerURLPattern = patternUnmarshal(`/provider-metadata\.json$`) var providerURLPattern = patternUnmarshal(`/provider-metadata\.json$`)
// ProviderMetadata contains the metadata of the provider.
type ProviderMetadata struct { type ProviderMetadata struct {
CanonicalURL *ProviderURL `json:"canonical_url"` // required CanonicalURL *ProviderURL `json:"canonical_url"` // required
Distributions []Distribution `json:"distributions,omitempty"` Distributions []Distribution `json:"distributions,omitempty"`
@ -117,7 +148,7 @@ type ProviderMetadata struct {
MetadataVersion *MetadataVersion `json:"metadata_version"` // required MetadataVersion *MetadataVersion `json:"metadata_version"` // required
MirrorOnCSAFAggregators *bool `json:"mirror_on_CSAF_aggregators"` // required MirrorOnCSAFAggregators *bool `json:"mirror_on_CSAF_aggregators"` // required
PGPKeys []PGPKey `json:"pgp_keys,omitempty"` PGPKeys []PGPKey `json:"pgp_keys,omitempty"`
Publisher *CSAFPublisher `json:"publisher"` // required Publisher *Publisher `json:"publisher"` // required
Role *MetadataRole `json:"role"` // required Role *MetadataRole `json:"role"` // required
} }
@ -144,6 +175,7 @@ func alternativesUnmarshal(alternatives ...string) func([]byte) (string, error)
} }
} }
// UnmarshalText implements the encoding.TextUnmarshaller interface.
func (tl *TLPLabel) UnmarshalText(data []byte) error { func (tl *TLPLabel) UnmarshalText(data []byte) error {
s, err := tlpLabelPattern(data) s, err := tlpLabelPattern(data)
if err == nil { if err == nil {
@ -152,14 +184,16 @@ func (tl *TLPLabel) UnmarshalText(data []byte) error {
return err return err
} }
func (ju *JsonURL) UnmarshalText(data []byte) error { // UnmarshalText implements the encoding.TextUnmarshaller interface.
func (ju *JSONURL) UnmarshalText(data []byte) error {
s, err := jsonURLPattern(data) s, err := jsonURLPattern(data)
if err == nil { if err == nil {
*ju = JsonURL(s) *ju = JSONURL(s)
} }
return err return err
} }
// UnmarshalText implements the encoding.TextUnmarshaller interface.
func (pu *ProviderURL) UnmarshalText(data []byte) error { func (pu *ProviderURL) UnmarshalText(data []byte) error {
s, err := providerURLPattern(data) s, err := providerURLPattern(data)
if err == nil { if err == nil {
@ -168,14 +202,16 @@ func (pu *ProviderURL) UnmarshalText(data []byte) error {
return err return err
} }
func (cc *CSAFCategory) UnmarshalText(data []byte) error { // UnmarshalText implements the encoding.TextUnmarshaller interface.
func (cc *Category) UnmarshalText(data []byte) error {
s, err := csafCategoryPattern(data) s, err := csafCategoryPattern(data)
if err == nil { if err == nil {
*cc = CSAFCategory(s) *cc = Category(s)
} }
return err return err
} }
// UnmarshalText implements the encoding.TextUnmarshaller interface.
func (fp *Fingerprint) UnmarshalText(data []byte) error { func (fp *Fingerprint) UnmarshalText(data []byte) error {
s, err := fingerprintPattern(data) s, err := fingerprintPattern(data)
if err == nil { if err == nil {
@ -184,6 +220,7 @@ func (fp *Fingerprint) UnmarshalText(data []byte) error {
return err return err
} }
// UnmarshalText implements the encoding.TextUnmarshaller interface.
func (ts *TimeStamp) UnmarshalText(data []byte) error { func (ts *TimeStamp) UnmarshalText(data []byte) error {
t, err := time.Parse(time.RFC3339, string(data)) t, err := time.Parse(time.RFC3339, string(data))
if err != nil { if err != nil {
@ -193,10 +230,12 @@ func (ts *TimeStamp) UnmarshalText(data []byte) error {
return nil return nil
} }
// MarshalText implements the encoding.TextMarshaller interface.
func (ts TimeStamp) MarshalText() ([]byte, error) { func (ts TimeStamp) MarshalText() ([]byte, error) {
return []byte(time.Time(ts).Format(time.RFC3339)), nil return []byte(time.Time(ts).Format(time.RFC3339)), nil
} }
// Defaults fills the correct default values into the provider metadata.
func (pmd *ProviderMetadata) Defaults() { func (pmd *ProviderMetadata) Defaults() {
if pmd.Role == nil { if pmd.Role == nil {
role := MetadataRoleProvider role := MetadataRoleProvider
@ -216,6 +255,8 @@ func (pmd *ProviderMetadata) Defaults() {
} }
} }
// Validate checks if the feed is valid.
// Returns an error if the validation fails otherwise nil.
func (f *Feed) Validate() error { func (f *Feed) Validate() error {
switch { switch {
case f.TLPLabel == nil: case f.TLPLabel == nil:
@ -226,6 +267,8 @@ func (f *Feed) Validate() error {
return nil return nil
} }
// Validate checks if the ROLIE extension is valid.
// Returns an error if the validation fails otherwise nil.
func (r *ROLIE) Validate() error { func (r *ROLIE) Validate() error {
if len(r.Feeds) < 1 { if len(r.Feeds) < 1 {
return errors.New("ROLIE needs at least one feed") return errors.New("ROLIE needs at least one feed")
@ -238,7 +281,9 @@ func (r *ROLIE) Validate() error {
return nil return nil
} }
func (cp *CSAFPublisher) Validate() error { // Validate checks if the publisher is valid.
// Returns an error if the validation fails otherwise nil.
func (cp *Publisher) Validate() error {
switch { switch {
case cp == nil: case cp == nil:
return errors.New("publisher is mandatory") return errors.New("publisher is mandatory")
@ -252,6 +297,8 @@ func (cp *CSAFPublisher) Validate() error {
return nil return nil
} }
// Validate checks if the PGPKey is valid.
// Returns an error if the validation fails otherwise nil.
func (pk *PGPKey) Validate() error { func (pk *PGPKey) Validate() error {
if pk.URL == nil { if pk.URL == nil {
return errors.New("pgp_key[].url is mandatory") return errors.New("pgp_key[].url is mandatory")
@ -259,6 +306,8 @@ func (pk *PGPKey) Validate() error {
return nil return nil
} }
// Validate checks if the distribution is valid.
// Returns an error if the validation fails otherwise nil.
func (d *Distribution) Validate() error { func (d *Distribution) Validate() error {
for i := range d.Rolie { for i := range d.Rolie {
if err := d.Rolie[i].Validate(); err != nil { if err := d.Rolie[i].Validate(); err != nil {
@ -268,6 +317,8 @@ func (d *Distribution) Validate() error {
return nil return nil
} }
// Validate checks if the provider metadata is valid.
// Returns an error if the validation fails otherwise nil.
func (pmd *ProviderMetadata) Validate() error { func (pmd *ProviderMetadata) Validate() error {
switch { switch {
@ -298,11 +349,16 @@ func (pmd *ProviderMetadata) Validate() error {
return nil return nil
} }
// SetLastUpdated updates the last updated timestamp of the feed.
func (pmd *ProviderMetadata) SetLastUpdated(t time.Time) { func (pmd *ProviderMetadata) SetLastUpdated(t time.Time) {
ts := TimeStamp(t.UTC()) ts := TimeStamp(t.UTC())
pmd.LastUpdated = &ts pmd.LastUpdated = &ts
} }
// SetPGP sets the fingerprint and URL of the OpenPGP key
// of the feed. If the feed already has a key with
// given fingerprint the URL updated.
// If there is no such key it is append to the list of keys.
func (pmd *ProviderMetadata) SetPGP(fingerprint, url string) { func (pmd *ProviderMetadata) SetPGP(fingerprint, url string) {
for i := range pmd.PGPKeys { for i := range pmd.PGPKeys {
if pmd.PGPKeys[i].Fingerprint == Fingerprint(fingerprint) { if pmd.PGPKeys[i].Fingerprint == Fingerprint(fingerprint) {
@ -316,21 +372,26 @@ func (pmd *ProviderMetadata) SetPGP(fingerprint, url string) {
}) })
} }
// NewProviderMetadata creates a new provider with the given URL.
// Valid default values are set and the feed is considered to
// be updated recently.
func NewProviderMetadata(canonicalURL string) *ProviderMetadata { func NewProviderMetadata(canonicalURL string) *ProviderMetadata {
pmd := new(ProviderMetadata) pm := new(ProviderMetadata)
pmd.Defaults() pm.Defaults()
pmd.SetLastUpdated(time.Now()) pm.SetLastUpdated(time.Now())
cu := ProviderURL(canonicalURL) cu := ProviderURL(canonicalURL)
pmd.CanonicalURL = &cu pm.CanonicalURL = &cu
return pmd return pm
} }
func (pm *ProviderMetadata) Save(w io.Writer) error { // Save saves a metadata provider to a writer.
func (pmd *ProviderMetadata) Save(w io.Writer) error {
enc := json.NewEncoder(w) enc := json.NewEncoder(w)
enc.SetIndent("", " ") enc.SetIndent("", " ")
return enc.Encode(pm) return enc.Encode(pmd)
} }
// LoadProviderMetadata loads a metadata provider from a reader.
func LoadProviderMetadata(r io.Reader) (*ProviderMetadata, error) { func LoadProviderMetadata(r io.Reader) (*ProviderMetadata, error) {
var pmd ProviderMetadata var pmd ProviderMetadata

View file

@ -7,30 +7,36 @@ import (
"time" "time"
) )
// Link for ROLIE.
type Link struct { type Link struct {
Rel string `json:"rel"` Rel string `json:"rel"`
HRef string `json:"href"` HRef string `json:"href"`
} }
type Category struct { // ROLIECategory for ROLIE.
type ROLIECategory struct {
Scheme string `json:"scheme"` Scheme string `json:"scheme"`
Term string `json:"term"` Term string `json:"term"`
} }
// Summary for ROLIE.
type Summary struct { type Summary struct {
Content string `json:"content"` Content string `json:"content"`
} }
// Content for ROLIE.
type Content struct { type Content struct {
Type string `json:"type"` Type string `json:"type"`
Src string `json:"src"` Src string `json:"src"`
} }
// Format for ROLIE.
type Format struct { type Format struct {
Schema string `json:"schema"` Schema string `json:"schema"`
Version string `json:"version"` Version string `json:"version"`
} }
// Entry for ROLIE.
type Entry struct { type Entry struct {
ID string `json:"id"` ID string `json:"id"`
Titel string `json:"title"` Titel string `json:"title"`
@ -42,15 +48,17 @@ type Entry struct {
Format Format `json:"format"` Format Format `json:"format"`
} }
// ROLIEFeed is a ROLIE feed.
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,omitempty"` Link []Link `json:"link,omitempty"`
Category []Category `json:"category,omitempty"` Category []ROLIECategory `json:"category,omitempty"`
Updated TimeStamp `json:"updated"` Updated TimeStamp `json:"updated"`
Entry []*Entry `json:"entry,omitempty"` Entry []*Entry `json:"entry,omitempty"`
} }
// LoadROLIEFeed loads a ROLIE feed from a reader.
func LoadROLIEFeed(r io.Reader) (*ROLIEFeed, error) { func LoadROLIEFeed(r io.Reader) (*ROLIEFeed, error) {
dec := json.NewDecoder(r) dec := json.NewDecoder(r)
var rf ROLIEFeed var rf ROLIEFeed
@ -60,12 +68,15 @@ func LoadROLIEFeed(r io.Reader) (*ROLIEFeed, error) {
return &rf, nil return &rf, nil
} }
// Save saves a ROLIE feed to a writer.
func (rf *ROLIEFeed) Save(w io.Writer) error { func (rf *ROLIEFeed) Save(w io.Writer) error {
enc := json.NewEncoder(w) enc := json.NewEncoder(w)
enc.SetIndent("", " ") enc.SetIndent("", " ")
return enc.Encode(rf) return enc.Encode(rf)
} }
// EntryByID looks up an entry by its ID.
// Returns nil if no such entry was found.
func (rf *ROLIEFeed) EntryByID(id string) *Entry { func (rf *ROLIEFeed) EntryByID(id string) *Entry {
for _, entry := range rf.Entry { for _, entry := range rf.Entry {
if entry.ID == id { if entry.ID == id {
@ -75,6 +86,8 @@ func (rf *ROLIEFeed) EntryByID(id string) *Entry {
return nil return nil
} }
// SortEntriesByUpdated sorts all the entries in the feed
// by their update times.
func (rf *ROLIEFeed) SortEntriesByUpdated() { func (rf *ROLIEFeed) SortEntriesByUpdated() {
entries := rf.Entry entries := rf.Entry
sort.Slice(entries, func(i, j int) bool { sort.Slice(entries, func(i, j int) bool {