From 04fb8f7e7542b227fe2c5b2c258fd9bc53ba7092 Mon Sep 17 00:00:00 2001 From: "Sascha L. Teichmann" Date: Thu, 25 Nov 2021 18:21:23 +0100 Subject: [PATCH] Fix golint warnings. --- cmd/csaf_provider/controller.go | 2 +- cmd/csaf_provider/extract.go | 4 +- cmd/csaf_provider/files.go | 3 +- cmd/csaf_provider/transaction.go | 2 +- csaf/models.go | 133 ++++++++++++++++++++++--------- csaf/rolie.go | 27 +++++-- 6 files changed, 122 insertions(+), 49 deletions(-) diff --git a/cmd/csaf_provider/controller.go b/cmd/csaf_provider/controller.go index 9a5cf14..d982334 100644 --- a/cmd/csaf_provider/controller.go +++ b/cmd/csaf_provider/controller.go @@ -248,7 +248,7 @@ func (c *controller) upload(rw http.ResponseWriter, r *http.Request) { return err } - feedURL := csaf.JsonURL( + feedURL := csaf.JSONURL( c.cfg.Domain + "/.well-known/csaf/" + ts + "/" + feedName) tlpLabel := csaf.TLPLabel(strings.ToUpper(ts)) diff --git a/cmd/csaf_provider/extract.go b/cmd/csaf_provider/extract.go index 411f455..4c8c955 100644 --- a/cmd/csaf_provider/extract.go +++ b/cmd/csaf_provider/extract.go @@ -26,7 +26,7 @@ const ( type extraction struct { id string title string - publisher *csaf.CSAFPublisher + publisher *csaf.Publisher initialReleaseDate time.Time currentReleaseDate time.Time summary string @@ -109,7 +109,7 @@ func (e *extraction) extractPublisher(path extractFunc) error { if err := enc.Encode(p); err != nil { return err } - e.publisher = new(csaf.CSAFPublisher) + e.publisher = new(csaf.Publisher) if err := json.Unmarshal(buf.Bytes(), e.publisher); err != nil { return err } diff --git a/cmd/csaf_provider/files.go b/cmd/csaf_provider/files.go index 3f5c71e..ed96913 100644 --- a/cmd/csaf_provider/files.go +++ b/cmd/csaf_provider/files.go @@ -42,9 +42,8 @@ func createSecurity(c *config) error { f, "CSAF: %s/.well-known/csaf/provider-metadata.json\n", c.Domain) return f.Close() - } else { - return err } + return err } return nil } diff --git a/cmd/csaf_provider/transaction.go b/cmd/csaf_provider/transaction.go index 886c53c..6663d09 100644 --- a/cmd/csaf_provider/transaction.go +++ b/cmd/csaf_provider/transaction.go @@ -24,7 +24,7 @@ func newProviderMetadata(cfg *config) *csaf.ProviderMetadata { var ( ts = string(t) feedName = "csaf-feed-tlp-" + ts + ".json" - feedURL = csaf.JsonURL( + feedURL = csaf.JSONURL( cfg.Domain + "/.well-known/csaf/" + ts + "/" + feedName) tlpLabel = csaf.TLPLabel(strings.ToUpper(ts)) ) diff --git a/csaf/models.go b/csaf/models.go index 4cb37de..29a9d1a 100644 --- a/csaf/models.go +++ b/csaf/models.go @@ -10,14 +10,20 @@ import ( "time" ) +// TLPLabel is the traffic light policy of the CSAF. type TLPLabel string const ( + // TLPLabelUnlabeled is the 'UNLABELED' policy. TLPLabelUnlabeled = "UNLABELED" - TLPLabelWhite = "WHITE" - TLPLabelGreen = "GREEN" - TLPLabelAmber = "AMBER" - TLPLabelRed = "RED" + // TLPLabelWhite is the 'WHITE' policy. + TLPLabelWhite = "WHITE" + // TLPLabelGreen is the 'GREEN' policy. + TLPLabelGreen = "GREEN" + // TLPLabelAmber is the 'AMBER' policy. + TLPLabelAmber = "AMBER" + // TLPLabelRed is the 'RED' policy. + TLPLabelRed = "RED" ) var tlpLabelPattern = alternativesUnmarshal( @@ -27,47 +33,63 @@ var tlpLabelPattern = alternativesUnmarshal( string("AMBER"), string("RED")) -type JsonURL string +// JSONURL is an URL to JSON document. +type JSONURL string var jsonURLPattern = patternUnmarshal(`\.json$`) +// Feed is CSAF feed. type Feed struct { Summary string `json:"summary"` 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 { - Categories []JsonURL `json:"categories,omitempty"` + Categories []JSONURL `json:"categories,omitempty"` 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 { DirectoryURL string `json:"directory_url,omitempty"` Rolie []ROLIE `json:"rolie"` } +// TimeStamp represents a time stamp in a CSAF feed. type TimeStamp time.Time +// Fingerprint is the fingerprint of a OpenPGP key used to sign +// the CASF documents. type Fingerprint string 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 { Fingerprint Fingerprint `json:"fingerprint,omitempty"` URL *string `json:"url"` // required } -type CSAFCategory string +// Category is the category of the CSAF feed. +type Category string const ( - CSAFCategoryCoordinator CSAFCategory = "coordinator" - CSAFCategoryDiscoverer CSAFCategory = "discoverer" - CSAFCategoryOther CSAFCategory = "other" - CSAFCategoryTranslator CSAFCategory = "translator" - CSAFCategoryUser CSAFCategory = "user" - CSAFCategoryVendor CSAFCategory = "vendor" + // CSAFCategoryCoordinator is the "coordinator" category. + CSAFCategoryCoordinator Category = "coordinator" + // CSAFCategoryDiscoverer is the "discoverer" category. + CSAFCategoryDiscoverer Category = "discoverer" + // CSAFCategoryOther is the "other" category. + 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( @@ -78,25 +100,32 @@ var csafCategoryPattern = alternativesUnmarshal( string(CSAFCategoryUser), string(CSAFCategoryVendor)) -type CSAFPublisher struct { - Category *CSAFCategory `json:"category"` // required - Name *string `json:"name"` // required - Namespace *string `json:"namespace"` // required - ContactDetails string `json:"contact_details,omitempty"` - IssuingAuthority string `json:"issuing_authority,omitempty"` +// Publisher is the publisher of the feed. +type Publisher struct { + Category *Category `json:"category"` // required + Name *string `json:"name"` // required + Namespace *string `json:"namespace"` // required + ContactDetails string `json:"contact_details,omitempty"` + IssuingAuthority string `json:"issuing_authority,omitempty"` } +// MetadataVersion is the metadata version of the feed. type MetadataVersion string +// MetadataVersion20 is the current version of the schema. const MetadataVersion20 MetadataVersion = "2.0" var metadataVersionPattern = alternativesUnmarshal(string(MetadataVersion20)) +// MetadataRole is the role of the feed. type MetadataRole string const ( - MetadataRolePublisher MetadataRole = "csaf_publisher" - MetadataRoleProvider MetadataRole = "csaf_provider" + // MetadataRolePublisher is the "csaf_publisher" role. + 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" ) @@ -105,10 +134,12 @@ var metadataRolePattern = alternativesUnmarshal( string(MetadataRoleProvider), string(MetadataRoleTrustedProvider)) +// ProviderURL is the URL of the provider document. type ProviderURL string var providerURLPattern = patternUnmarshal(`/provider-metadata\.json$`) +// ProviderMetadata contains the metadata of the provider. type ProviderMetadata struct { CanonicalURL *ProviderURL `json:"canonical_url"` // required Distributions []Distribution `json:"distributions,omitempty"` @@ -117,7 +148,7 @@ type ProviderMetadata struct { MetadataVersion *MetadataVersion `json:"metadata_version"` // required MirrorOnCSAFAggregators *bool `json:"mirror_on_CSAF_aggregators"` // required PGPKeys []PGPKey `json:"pgp_keys,omitempty"` - Publisher *CSAFPublisher `json:"publisher"` // required + Publisher *Publisher `json:"publisher"` // 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 { s, err := tlpLabelPattern(data) if err == nil { @@ -152,14 +184,16 @@ func (tl *TLPLabel) UnmarshalText(data []byte) error { 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) if err == nil { - *ju = JsonURL(s) + *ju = JSONURL(s) } return err } +// UnmarshalText implements the encoding.TextUnmarshaller interface. func (pu *ProviderURL) UnmarshalText(data []byte) error { s, err := providerURLPattern(data) if err == nil { @@ -168,14 +202,16 @@ func (pu *ProviderURL) UnmarshalText(data []byte) error { 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) if err == nil { - *cc = CSAFCategory(s) + *cc = Category(s) } return err } +// UnmarshalText implements the encoding.TextUnmarshaller interface. func (fp *Fingerprint) UnmarshalText(data []byte) error { s, err := fingerprintPattern(data) if err == nil { @@ -184,6 +220,7 @@ func (fp *Fingerprint) UnmarshalText(data []byte) error { return err } +// UnmarshalText implements the encoding.TextUnmarshaller interface. func (ts *TimeStamp) UnmarshalText(data []byte) error { t, err := time.Parse(time.RFC3339, string(data)) if err != nil { @@ -193,10 +230,12 @@ func (ts *TimeStamp) UnmarshalText(data []byte) error { return nil } +// MarshalText implements the encoding.TextMarshaller interface. func (ts TimeStamp) MarshalText() ([]byte, error) { return []byte(time.Time(ts).Format(time.RFC3339)), nil } +// Defaults fills the correct default values into the provider metadata. func (pmd *ProviderMetadata) Defaults() { if pmd.Role == nil { 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 { switch { case f.TLPLabel == nil: @@ -226,6 +267,8 @@ func (f *Feed) Validate() error { return nil } +// Validate checks if the ROLIE extension is valid. +// Returns an error if the validation fails otherwise nil. func (r *ROLIE) Validate() error { if len(r.Feeds) < 1 { return errors.New("ROLIE needs at least one feed") @@ -238,7 +281,9 @@ func (r *ROLIE) Validate() error { 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 { case cp == nil: return errors.New("publisher is mandatory") @@ -252,6 +297,8 @@ func (cp *CSAFPublisher) Validate() error { return nil } +// Validate checks if the PGPKey is valid. +// Returns an error if the validation fails otherwise nil. func (pk *PGPKey) Validate() error { if pk.URL == nil { return errors.New("pgp_key[].url is mandatory") @@ -259,6 +306,8 @@ func (pk *PGPKey) Validate() error { return nil } +// Validate checks if the distribution is valid. +// Returns an error if the validation fails otherwise nil. func (d *Distribution) Validate() error { for i := range d.Rolie { if err := d.Rolie[i].Validate(); err != nil { @@ -268,6 +317,8 @@ func (d *Distribution) Validate() error { return nil } +// Validate checks if the provider metadata is valid. +// Returns an error if the validation fails otherwise nil. func (pmd *ProviderMetadata) Validate() error { switch { @@ -298,11 +349,16 @@ func (pmd *ProviderMetadata) Validate() error { return nil } +// SetLastUpdated updates the last updated timestamp of the feed. func (pmd *ProviderMetadata) SetLastUpdated(t time.Time) { ts := TimeStamp(t.UTC()) 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) { for i := range pmd.PGPKeys { 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 { - pmd := new(ProviderMetadata) - pmd.Defaults() - pmd.SetLastUpdated(time.Now()) + pm := new(ProviderMetadata) + pm.Defaults() + pm.SetLastUpdated(time.Now()) cu := ProviderURL(canonicalURL) - pmd.CanonicalURL = &cu - return pmd + pm.CanonicalURL = &cu + 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.SetIndent("", " ") - return enc.Encode(pm) + return enc.Encode(pmd) } +// LoadProviderMetadata loads a metadata provider from a reader. func LoadProviderMetadata(r io.Reader) (*ProviderMetadata, error) { var pmd ProviderMetadata diff --git a/csaf/rolie.go b/csaf/rolie.go index 8e19b86..e49641f 100644 --- a/csaf/rolie.go +++ b/csaf/rolie.go @@ -7,30 +7,36 @@ import ( "time" ) +// Link for ROLIE. type Link struct { Rel string `json:"rel"` HRef string `json:"href"` } -type Category struct { +// ROLIECategory for ROLIE. +type ROLIECategory struct { Scheme string `json:"scheme"` Term string `json:"term"` } +// Summary for ROLIE. type Summary struct { Content string `json:"content"` } +// Content for ROLIE. type Content struct { Type string `json:"type"` Src string `json:"src"` } +// Format for ROLIE. type Format struct { Schema string `json:"schema"` Version string `json:"version"` } +// Entry for ROLIE. type Entry struct { ID string `json:"id"` Titel string `json:"title"` @@ -42,15 +48,17 @@ type Entry struct { Format Format `json:"format"` } +// ROLIEFeed is a ROLIE feed. type ROLIEFeed struct { - ID string `json:"id"` - Title string `json:"title"` - Link []Link `json:"link,omitempty"` - Category []Category `json:"category,omitempty"` - Updated TimeStamp `json:"updated"` - Entry []*Entry `json:"entry,omitempty"` + ID string `json:"id"` + Title string `json:"title"` + Link []Link `json:"link,omitempty"` + Category []ROLIECategory `json:"category,omitempty"` + Updated TimeStamp `json:"updated"` + Entry []*Entry `json:"entry,omitempty"` } +// LoadROLIEFeed loads a ROLIE feed from a reader. func LoadROLIEFeed(r io.Reader) (*ROLIEFeed, error) { dec := json.NewDecoder(r) var rf ROLIEFeed @@ -60,12 +68,15 @@ func LoadROLIEFeed(r io.Reader) (*ROLIEFeed, error) { return &rf, nil } +// Save saves a ROLIE feed to a writer. func (rf *ROLIEFeed) Save(w io.Writer) error { enc := json.NewEncoder(w) enc.SetIndent("", " ") 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 { for _, entry := range rf.Entry { if entry.ID == id { @@ -75,6 +86,8 @@ func (rf *ROLIEFeed) EntryByID(id string) *Entry { return nil } +// SortEntriesByUpdated sorts all the entries in the feed +// by their update times. func (rf *ROLIEFeed) SortEntriesByUpdated() { entries := rf.Entry sort.Slice(entries, func(i, j int) bool {