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

Improve download handler interface

This commit is contained in:
koplas 2024-06-24 13:29:46 +02:00
parent 513282a7a8
commit fe12aaf993
No known key found for this signature in database
2 changed files with 67 additions and 44 deletions

View file

@ -11,6 +11,7 @@ package main
import ( import (
"context" "context"
"encoding/json"
"log/slog" "log/slog"
"os" "os"
"os/signal" "os/signal"
@ -19,9 +20,12 @@ import (
"strconv" "strconv"
"strings" "strings"
"sync" "sync"
"time"
"github.com/csaf-poc/csaf_distribution/v3/csaf"
"github.com/csaf-poc/csaf_distribution/v3/internal/options" "github.com/csaf-poc/csaf_distribution/v3/internal/options"
"github.com/csaf-poc/csaf_distribution/v3/lib/downloader" "github.com/csaf-poc/csaf_distribution/v3/lib/downloader"
"github.com/csaf-poc/csaf_distribution/v3/util"
) )
// failedForwardDir is the name of the special sub folder // failedForwardDir is the name of the special sub folder
@ -79,6 +83,35 @@ func mkdirAll(path string, perm os.FileMode) error {
return os.MkdirAll(path, perm) return os.MkdirAll(path, perm)
} }
func extractInitialReleaseDate(doc any) time.Time {
var initialReleaseDate time.Time
dateExtract := util.TimeMatcher(&initialReleaseDate, time.RFC3339)
eval := util.NewPathEval()
if err := eval.Extract(
`$.document.tracking.initial_release_date`, dateExtract, false, doc,
); err != nil {
slog.Warn("Cannot extract initial_release_date from advisory")
initialReleaseDate = time.Now()
}
initialReleaseDate = initialReleaseDate.UTC()
return initialReleaseDate
}
func extractTLP(doc any) csaf.TLPLabel {
eval := util.NewPathEval()
labelString, err := eval.Eval(`$.document.distribution.tlp.label`, doc)
if err != nil {
return csaf.TLPLabelUnlabeled
}
label, ok := labelString.(string)
if !ok {
return csaf.TLPLabelUnlabeled
}
return csaf.TLPLabel(label)
}
func downloadHandler(cfg *config) func(d downloader.DownloadedDocument) error { func downloadHandler(cfg *config) func(d downloader.DownloadedDocument) error {
return func(d downloader.DownloadedDocument) error { return func(d downloader.DownloadedDocument) error {
if cfg.NoStore { if cfg.NoStore {
@ -98,13 +131,22 @@ func downloadHandler(cfg *config) func(d downloader.DownloadedDocument) error {
newDir = cfg.Directory newDir = cfg.Directory
} }
lower := strings.ToLower(string(d.Label)) var doc any
if err := json.Unmarshal(d.Data, &doc); err != nil {
slog.Error("Could not parse json document", "err", err)
return nil
}
initialReleaseDate := extractInitialReleaseDate(doc)
label := extractTLP(doc)
lower := strings.ToLower(string(label))
// Do we have a configured destination folder? // Do we have a configured destination folder?
if cfg.Folder != "" { if cfg.Folder != "" {
newDir = path.Join(newDir, cfg.Folder) newDir = path.Join(newDir, cfg.Folder)
} else { } else {
newDir = path.Join(newDir, lower, strconv.Itoa(d.InitialReleaseDate.Year())) newDir = path.Join(newDir, lower, strconv.Itoa(initialReleaseDate.Year()))
} }
if newDir != lastDir { if newDir != lastDir {
@ -121,9 +163,9 @@ func downloadHandler(cfg *config) func(d downloader.DownloadedDocument) error {
p string p string
d []byte d []byte
}{ }{
{filePath, d.Data.Bytes()}, {filePath, d.Data},
{filePath + ".sha256", d.S256Data}, {filePath + ".sha256", d.SHA256},
{filePath + ".sha512", d.S512Data}, {filePath + ".sha512", d.SHA512},
{filePath + ".asc", d.SignData}, {filePath + ".asc", d.SignData},
} { } {
if x.d != nil { if x.d != nil {
@ -157,8 +199,8 @@ func storeFailedAdvisory(cfg *config) func(filename, doc, sha256, sha512 string)
{filename + ".sha512", sha512}, {filename + ".sha512", sha512},
} { } {
if len(x.d) != 0 { if len(x.d) != 0 {
path := filepath.Join(dir, x.p) p := filepath.Join(dir, x.p)
if err := os.WriteFile(path, []byte(x.d), 0644); err != nil { if err := os.WriteFile(p, []byte(x.d), 0644); err != nil {
return err return err
} }
} }

View file

@ -38,6 +38,7 @@ import (
type Downloader struct { type Downloader struct {
cfg *Config cfg *Config
keys *crypto.KeyRing keys *crypto.KeyRing
eval *util.PathEval
validator csaf.RemoteValidator validator csaf.RemoteValidator
Forwarder *Forwarder Forwarder *Forwarder
mkdirMu sync.Mutex mkdirMu sync.Mutex
@ -47,14 +48,12 @@ type Downloader struct {
// DownloadedDocument contains the document data with additional metadata. // DownloadedDocument contains the document data with additional metadata.
type DownloadedDocument struct { type DownloadedDocument struct {
Data bytes.Buffer Data []byte
S256Data []byte SHA256 []byte
S512Data []byte SHA512 []byte
SignData []byte SignData []byte
InitialReleaseDate time.Time
Filename string Filename string
ValStatus ValidationStatus ValStatus ValidationStatus
Label csaf.TLPLabel
} }
// failedValidationDir is the name of the sub folder // failedValidationDir is the name of the sub folder
@ -64,7 +63,6 @@ const failedValidationDir = "failed_validation"
// NewDownloader constructs a new downloader given the configuration. // NewDownloader constructs a new downloader given the configuration.
func NewDownloader(cfg *Config) (*Downloader, error) { func NewDownloader(cfg *Config) (*Downloader, error) {
var validator csaf.RemoteValidator var validator csaf.RemoteValidator
if cfg.RemoteValidator != "" { if cfg.RemoteValidator != "" {
@ -117,7 +115,6 @@ func logRedirect(logger *slog.Logger) func(req *http.Request, via []*http.Reques
} }
func (d *Downloader) httpClient() util.Client { func (d *Downloader) httpClient() util.Client {
hClient := http.Client{} hClient := http.Client{}
if d.cfg.verbose() { if d.cfg.verbose() {
@ -258,16 +255,14 @@ func (d *Downloader) download(ctx context.Context, domain string) error {
} }
return afp.Process(func(label csaf.TLPLabel, files []csaf.AdvisoryFile) error { return afp.Process(func(label csaf.TLPLabel, files []csaf.AdvisoryFile) error {
return d.downloadFiles(ctx, label, files) return d.downloadFiles(ctx, files)
}) })
} }
func (d *Downloader) downloadFiles( func (d *Downloader) downloadFiles(
ctx context.Context, ctx context.Context,
label csaf.TLPLabel,
files []csaf.AdvisoryFile, files []csaf.AdvisoryFile,
) error { ) error {
var ( var (
advisoryCh = make(chan csaf.AdvisoryFile) advisoryCh = make(chan csaf.AdvisoryFile)
errorCh = make(chan error) errorCh = make(chan error)
@ -291,7 +286,7 @@ func (d *Downloader) downloadFiles(
for i := 0; i < n; i++ { for i := 0; i < n; i++ {
wg.Add(1) wg.Add(1)
go d.downloadWorker(ctx, &wg, label, advisoryCh, errorCh) go d.downloadWorker(ctx, &wg, advisoryCh, errorCh)
} }
allFiles: allFiles:
@ -370,7 +365,6 @@ func (d *Downloader) loadOpenPGPKeys(
defer res.Body.Close() defer res.Body.Close()
return crypto.NewKeyFromArmoredReader(res.Body) return crypto.NewKeyFromArmoredReader(res.Body)
}() }()
if err != nil { if err != nil {
d.cfg.Logger.Warn( d.cfg.Logger.Warn(
"Reading public OpenPGP key failed", "Reading public OpenPGP key failed",
@ -425,7 +419,6 @@ func (d *Downloader) logValidationIssues(url string, errors []string, err error)
func (d *Downloader) downloadWorker( func (d *Downloader) downloadWorker(
ctx context.Context, ctx context.Context,
wg *sync.WaitGroup, wg *sync.WaitGroup,
label csaf.TLPLabel,
files <-chan csaf.AdvisoryFile, files <-chan csaf.AdvisoryFile,
errorCh chan<- error, errorCh chan<- error,
) { ) {
@ -434,8 +427,6 @@ func (d *Downloader) downloadWorker(
var ( var (
client = d.httpClient() client = d.httpClient()
data bytes.Buffer data bytes.Buffer
initialReleaseDate time.Time
dateExtract = util.TimeMatcher(&initialReleaseDate, time.RFC3339)
stats = stats{} stats = stats{}
expr = util.NewPathEval() expr = util.NewPathEval()
) )
@ -659,24 +650,14 @@ nextAdvisory:
string(s256Data), string(s256Data),
string(s512Data)) string(s512Data))
} }
if err := expr.Extract(
`$.document.tracking.initial_release_date`, dateExtract, false, doc,
); err != nil {
slog.Warn("Cannot extract initial_release_date from advisory",
"url", file.URL())
initialReleaseDate = time.Now()
}
initialReleaseDate = initialReleaseDate.UTC()
download := DownloadedDocument{ download := DownloadedDocument{
Data: data, Data: data.Bytes(),
S256Data: s256Data, SHA256: s256Data,
S512Data: s512Data, SHA512: s512Data,
SignData: signData, SignData: signData,
InitialReleaseDate: initialReleaseDate,
Filename: filename, Filename: filename,
ValStatus: valStatus, ValStatus: valStatus,
Label: label,
} }
err = d.cfg.DownloadHandler(download) err = d.cfg.DownloadHandler(download)