mirror of
https://github.com/gocsaf/csaf.git
synced 2025-12-22 05:40:11 +01:00
Fix golint warnings.
This commit is contained in:
parent
6b05323271
commit
04fb8f7e75
6 changed files with 122 additions and 49 deletions
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
)
|
||||
|
|
|
|||
133
csaf/models.go
133
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
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue