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

Read publisher from config.

This commit is contained in:
Sascha L. Teichmann 2021-12-01 19:27:46 +01:00
parent 37d6692fa8
commit 70eb8875a4
5 changed files with 163 additions and 131 deletions

View file

@ -6,6 +6,7 @@ import (
"strings" "strings"
"github.com/BurntSushi/toml" "github.com/BurntSushi/toml"
"github.com/csaf-poc/csaf_distribution/csaf"
) )
const ( const (
@ -17,14 +18,15 @@ const (
) )
type config struct { type config struct {
Key string `toml:"key"` Key string `toml:"key"`
Folder string `toml:"folder"` Folder string `toml:"folder"`
Web string `toml:"web"` Web string `toml:"web"`
TLPs []tlp `toml:"tlps"` TLPs []tlp `toml:"tlps"`
UploadSignature bool `toml:"upload_signature"` UploadSignature bool `toml:"upload_signature"`
PGPURL string `toml:"pgp_url"` PGPURL string `toml:"pgp_url"`
Domain string `toml:"domain"` Domain string `toml:"domain"`
NoPassphrase bool `toml:"no_passphrase"` NoPassphrase bool `toml:"no_passphrase"`
Publisher *csaf.Publisher `toml:"publisher"`
} }
type tlp string type tlp string
@ -58,6 +60,16 @@ func (cfg *config) GetPGPURL(key string) string {
return strings.ReplaceAll(cfg.PGPURL, "${KEY}", key) return strings.ReplaceAll(cfg.PGPURL, "${KEY}", key)
} }
func (cfg *config) modelTLPs() []csaf.TLPLabel {
tlps := make([]csaf.TLPLabel, len(cfg.TLPs))
for _, t := range cfg.TLPs {
if t != tlpCSAF {
tlps = append(tlps, csaf.TLPLabel(t))
}
}
return tlps
}
func loadConfig() (*config, error) { func loadConfig() (*config, error) {
path := os.Getenv(configEnv) path := os.Getenv(configEnv)
if path == "" { if path == "" {

View file

@ -0,0 +1,99 @@
package main
import (
"errors"
"fmt"
"os"
"path/filepath"
"github.com/csaf-poc/csaf_distribution/csaf"
)
func ensureFolders(c *config) error {
wellknown := filepath.Join(c.Web, ".well-known")
wellknownCSAF := filepath.Join(wellknown, "csaf")
if err := createWellknown(wellknownCSAF); err != nil {
return err
}
if err := createFeedFolders(c, wellknownCSAF); err != nil {
return err
}
if err := createProviderMetadata(c, wellknownCSAF); err != nil {
return err
}
return createSecurity(c, wellknown)
}
func createWellknown(wellknown string) error {
st, err := os.Stat(wellknown)
if err != nil {
if os.IsNotExist(err) {
return os.MkdirAll(wellknown, 0755)
}
return err
}
if !st.IsDir() {
return errors.New(".well-known/csaf is not a directory")
}
return nil
}
func createFeedFolders(c *config, wellknown string) error {
for _, t := range c.TLPs {
if t == tlpCSAF {
continue
}
tlpLink := filepath.Join(wellknown, string(t))
if _, err := filepath.EvalSymlinks(tlpLink); err != nil {
if os.IsNotExist(err) {
tlpFolder := filepath.Join(c.Folder, string(t))
if tlpFolder, err = mkUniqDir(tlpFolder); err != nil {
return err
}
if err = os.Symlink(tlpFolder, tlpLink); err != nil {
return err
}
} else {
return err
}
}
}
return nil
}
func createSecurity(c *config, wellknown string) error {
security := filepath.Join(wellknown, "security.txt")
if _, err := os.Stat(security); err != nil {
if os.IsNotExist(err) {
f, err := os.Create(security)
if err != nil {
return err
}
fmt.Fprintf(
f, "CSAF: %s/.well-known/csaf/provider-metadata.json\n",
c.Domain)
return f.Close()
}
return err
}
return nil
}
func createProviderMetadata(c *config, wellknownCSAF string) error {
path := filepath.Join(wellknownCSAF, "provider-metadata.json")
_, err := os.Stat(path)
if err == nil {
return nil
}
if !os.IsNotExist(err) {
return err
}
pm := csaf.NewProviderMetadataDomain(c.Domain, c.modelTLPs())
pm.Publisher = c.Publisher
return saveToFile(path, pm)
}

View file

@ -4,7 +4,6 @@ import (
"bytes" "bytes"
"crypto/sha256" "crypto/sha256"
"crypto/sha512" "crypto/sha512"
"errors"
"fmt" "fmt"
"hash" "hash"
"io" "io"
@ -16,81 +15,6 @@ import (
"time" "time"
) )
func ensureFolders(c *config) error {
wellknown, err := createWellknown(c)
if err != nil {
return err
}
if err := createFeedFolders(c, wellknown); err != nil {
return err
}
return createSecurity(c, wellknown)
}
func createSecurity(c *config, wellknown string) error {
security := filepath.Join(wellknown, "security.txt")
if _, err := os.Stat(security); err != nil {
if os.IsNotExist(err) {
f, err := os.Create(security)
if err != nil {
return err
}
fmt.Fprintf(
f, "CSAF: %s/.well-known/csaf/provider-metadata.json\n",
c.Domain)
return f.Close()
}
return err
}
return nil
}
func createFeedFolders(c *config, wellknown string) error {
for _, t := range c.TLPs {
if t == tlpCSAF {
continue
}
tlpLink := filepath.Join(wellknown, string(t))
if _, err := filepath.EvalSymlinks(tlpLink); err != nil {
if os.IsNotExist(err) {
tlpFolder := filepath.Join(c.Folder, string(t))
if tlpFolder, err = mkUniqDir(tlpFolder); err != nil {
return err
}
if err = os.Symlink(tlpFolder, tlpLink); err != nil {
return err
}
} else {
return err
}
}
}
return nil
}
func createWellknown(c *config) (string, error) {
wellknown := filepath.Join(c.Web, ".well-known", "csaf")
st, err := os.Stat(wellknown)
if err != nil {
if os.IsNotExist(err) {
if err := os.MkdirAll(wellknown, 0755); err != nil {
return "", err
}
} else {
return "", err
}
} else {
if !st.IsDir() {
return "", errors.New(".well-known/csaf is not a directory")
}
}
return wellknown, nil
}
func deepCopy(dst, src string) error { func deepCopy(dst, src string) error {
stack := []string{dst, src} stack := []string{dst, src}

View file

@ -3,49 +3,10 @@ package main
import ( import (
"os" "os"
"path/filepath" "path/filepath"
"strings"
"github.com/csaf-poc/csaf_distribution/csaf" "github.com/csaf-poc/csaf_distribution/csaf"
) )
func newProviderMetadata(cfg *config) *csaf.ProviderMetadata {
pmd := csaf.NewProviderMetadata(
cfg.Domain + "/.wellknown/csaf/provider-metadata.json")
// Register feeds.
var feeds []csaf.Feed
for _, t := range cfg.TLPs {
if t == tlpCSAF {
continue
}
var (
ts = string(t)
feedName = "csaf-feed-tlp-" + ts + ".json"
feedURL = csaf.JSONURL(
cfg.Domain + "/.well-known/csaf/" + ts + "/" + feedName)
tlpLabel = csaf.TLPLabel(strings.ToUpper(ts))
)
feeds = append(feeds, csaf.Feed{
Summary: "TLP:" + string(tlpLabel) + " advisories",
TLPLabel: &tlpLabel,
URL: &feedURL,
})
}
if len(feeds) > 0 {
pmd.Distributions = []csaf.Distribution{{
Rolie: []csaf.ROLIE{{
Feeds: feeds,
}},
}}
}
return pmd
}
func doTransaction( func doTransaction(
cfg *config, cfg *config,
t tlp, t tlp,
@ -60,7 +21,7 @@ func doTransaction(
f, err := os.Open(metadata) f, err := os.Open(metadata)
if err != nil { if err != nil {
if os.IsNotExist(err) { if os.IsNotExist(err) {
return newProviderMetadata(cfg), nil return csaf.NewProviderMetadataDomain(cfg.Domain, cfg.modelTLPs()), nil
} }
return nil, err return nil, err
} }

View file

@ -102,11 +102,11 @@ var csafCategoryPattern = alternativesUnmarshal(
// Publisher is the publisher of the feed. // Publisher is the publisher of the feed.
type Publisher struct { type Publisher struct {
Category *Category `json:"category"` // required Category *Category `json:"category" toml:"category"` // required
Name *string `json:"name"` // required Name *string `json:"name" toml:"name"` // required
Namespace *string `json:"namespace"` // required Namespace *string `json:"namespace" toml:"namespace"` // required
ContactDetails string `json:"contact_details,omitempty"` ContactDetails string `json:"contact_details,omitempty" toml:"contact_details"`
IssuingAuthority string `json:"issuing_authority,omitempty"` IssuingAuthority string `json:"issuing_authority,omitempty" toml:"issuing_authority"`
} }
// MetadataVersion is the metadata version of the feed. // MetadataVersion is the metadata version of the feed.
@ -148,8 +148,8 @@ 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 *Publisher `json:"publisher"` // required Publisher *Publisher `json:"publisher,omitempty"` // required
Role *MetadataRole `json:"role"` // required Role *MetadataRole `json:"role"` // required
} }
func patternUnmarshal(pattern string) func([]byte) (string, error) { func patternUnmarshal(pattern string) func([]byte) (string, error) {
@ -384,6 +384,42 @@ func NewProviderMetadata(canonicalURL string) *ProviderMetadata {
return pm return pm
} }
// NewProviderMetadataDomain creates a new provider with the given URL
// and tlps feeds.
func NewProviderMetadataDomain(domain string, tlps []TLPLabel) *ProviderMetadata {
pm := NewProviderMetadata(
domain + "/.wellknown/csaf/provider-metadata.json")
// Register feeds.
var feeds []Feed
for _, t := range tlps {
var (
ts = strings.ToLower(string(t))
feedName = "csaf-feed-tlp-" + ts + ".json"
feedURL = JSONURL(
domain + "/.well-known/csaf/" + ts + "/" + feedName)
)
feeds = append(feeds, Feed{
Summary: "TLP:" + string(t) + " advisories",
TLPLabel: &t,
URL: &feedURL,
})
}
if len(feeds) > 0 {
pm.Distributions = []Distribution{{
Rolie: []ROLIE{{
Feeds: feeds,
}},
}}
}
return pm
}
// Save saves a metadata provider to a writer. // Save saves a metadata provider to a writer.
func (pmd *ProviderMetadata) Save(w io.Writer) error { func (pmd *ProviderMetadata) Save(w io.Writer) error {
enc := json.NewEncoder(w) enc := json.NewEncoder(w)