1
0
Fork 0
mirror of https://github.com/gocsaf/csaf.git synced 2025-12-22 18:15:42 +01:00

Remove unnecessary URL joins

This should avoid bugs for more complex scenarios.
This commit is contained in:
koplas 2025-08-26 18:47:53 +02:00
parent 100e4d395b
commit fe77d496a2
No known key found for this signature in database
5 changed files with 41 additions and 70 deletions

View file

@ -67,17 +67,16 @@ func (w *worker) mirrorInternal() (*csaf.AggregatorCSAFProvider, error) {
// Collecting the categories per label. // Collecting the categories per label.
w.categories = map[string]util.Set[string]{} w.categories = map[string]util.Set[string]{}
base, err := url.Parse(w.loc) pmdURL, err := url.Parse(w.loc)
if err != nil { if err != nil {
return nil, err return nil, err
} }
base.Path = ""
afp := csaf.NewAdvisoryFileProcessor( afp := csaf.NewAdvisoryFileProcessor(
w.client, w.client,
w.expr, w.expr,
w.metadataProvider, w.metadataProvider,
base) pmdURL)
afp.AgeAccept = w.provider.ageAccept(w.processor.cfg) afp.AgeAccept = w.provider.ageAccept(w.processor.cfg)

View file

@ -628,14 +628,9 @@ var yearFromURL = regexp.MustCompile(`.*/(\d{4})/[^/]+$`)
// mistakes, from conforming filenames to invalid advisories. // mistakes, from conforming filenames to invalid advisories.
func (p *processor) integrity( func (p *processor) integrity(
files []csaf.AdvisoryFile, files []csaf.AdvisoryFile,
base string,
mask whereType, mask whereType,
lg func(MessageType, string, ...any), lg func(MessageType, string, ...any),
) error { ) error {
b, err := url.Parse(base)
if err != nil {
return err
}
client := p.httpClient() client := p.httpClient()
var data bytes.Buffer var data bytes.Buffer
@ -647,7 +642,7 @@ func (p *processor) integrity(
continue continue
} }
u := misc.JoinURL(b, fp).String() u := fp.String()
// Should this URL be ignored? // Should this URL be ignored?
if p.cfg.ignoreURL(u) { if p.cfg.ignoreURL(u) {
@ -779,7 +774,7 @@ func (p *processor) integrity(
lg(ErrorType, "Bad URL %s: %v", x.url(), err) lg(ErrorType, "Bad URL %s: %v", x.url(), err)
continue continue
} }
hashFile := misc.JoinURL(b, hu).String() hashFile := hu.String()
p.checkTLS(hashFile) p.checkTLS(hashFile)
if res, err = client.Get(hashFile); err != nil { if res, err = client.Get(hashFile); err != nil {
@ -828,7 +823,7 @@ func (p *processor) integrity(
lg(ErrorType, "Bad URL %s: %v", f.SignURL(), err) lg(ErrorType, "Bad URL %s: %v", f.SignURL(), err)
continue continue
} }
sigFile := misc.JoinURL(b, su).String() sigFile := su.String()
p.checkTLS(sigFile) p.checkTLS(sigFile)
p.badSignatures.use() p.badSignatures.use()
@ -948,12 +943,13 @@ func (p *processor) checkIndex(base string, mask whereType) error {
scanner := bufio.NewScanner(res.Body) scanner := bufio.NewScanner(res.Body)
for line := 1; scanner.Scan(); line++ { for line := 1; scanner.Scan(); line++ {
u := scanner.Text() u := scanner.Text()
if _, err := url.Parse(u); err != nil { up, err := url.Parse(u)
if err != nil {
p.badIntegrities.error("index.txt contains invalid URL %q in line %d", u, line) p.badIntegrities.error("index.txt contains invalid URL %q in line %d", u, line)
continue continue
} }
files = append(files, csaf.DirectoryAdvisoryFile{Path: u}) files = append(files, csaf.DirectoryAdvisoryFile{Path: misc.JoinURL(bu, up).String()})
} }
return files, scanner.Err() return files, scanner.Err()
}() }()
@ -968,7 +964,7 @@ func (p *processor) checkIndex(base string, mask whereType) error {
// Block rolie checks. // Block rolie checks.
p.labelChecker.feedLabel = "" p.labelChecker.feedLabel = ""
return p.integrity(files, base, mask, p.badIndices.add) return p.integrity(files, mask, p.badIndices.add)
} }
// checkChanges fetches the "changes.csv" and calls the "checkTLS" method for HTTPs checks. // checkChanges fetches the "changes.csv" and calls the "checkTLS" method for HTTPs checks.
@ -1035,8 +1031,13 @@ func (p *processor) checkChanges(base string, mask whereType) error {
} }
path := r[pathColumn] path := r[pathColumn]
pathURL, err := url.Parse(path)
if err != nil {
return nil, nil, err
}
times, files = append(times, t), times, files = append(times, t),
append(files, csaf.DirectoryAdvisoryFile{Path: path}) append(files, csaf.DirectoryAdvisoryFile{Path: misc.JoinURL(bu, pathURL).String()})
p.timesChanges[path] = t p.timesChanges[path] = t
} }
return times, files, nil return times, files, nil
@ -1063,7 +1064,7 @@ func (p *processor) checkChanges(base string, mask whereType) error {
// Block rolie checks. // Block rolie checks.
p.labelChecker.feedLabel = "" p.labelChecker.feedLabel = ""
return p.integrity(files, base, mask, p.badChanges.add) return p.integrity(files, mask, p.badChanges.add)
} }
// empty checks if list of strings contains at least one none empty string. // empty checks if list of strings contains at least one none empty string.
@ -1364,18 +1365,11 @@ func (p *processor) checkSecurityFolder(folder string) string {
} }
// Try to load // Try to load
up, err := url.Parse(u) _, err = url.Parse(u)
if err != nil { if err != nil {
return fmt.Sprintf("CSAF URL '%s' invalid: %v", u, err) return fmt.Sprintf("CSAF URL '%s' invalid: %v", u, err)
} }
base, err := url.Parse(folder)
if err != nil {
return err.Error()
}
base.Path = ""
u = misc.JoinURL(base, up).String()
p.checkTLS(u) p.checkTLS(u)
if res, err = client.Get(u); err != nil { if res, err = client.Get(u); err != nil {
return fmt.Sprintf("Cannot fetch %s from security.txt: %v", u, err) return fmt.Sprintf("Cannot fetch %s from security.txt: %v", u, err)
@ -1523,12 +1517,6 @@ func (p *processor) checkPGPKeys(_ string) error {
client := p.httpClient() client := p.httpClient()
base, err := url.Parse(p.pmdURL)
if err != nil {
return err
}
base.Path = ""
for i := range keys { for i := range keys {
key := &keys[i] key := &keys[i]
if key.URL == nil { if key.URL == nil {
@ -1541,10 +1529,11 @@ func (p *processor) checkPGPKeys(_ string) error {
continue continue
} }
u := misc.JoinURL(base, up).String() // Todo: refactor all methods to directly accept *url.URL
u := up.String()
p.checkTLS(u) p.checkTLS(u)
res, err := client.Get(u) res, err := client.Get(*key.URL)
if err != nil { if err != nil {
p.badPGPs.error("Fetching public OpenPGP key %s failed: %v.", u, err) p.badPGPs.error("Fetching public OpenPGP key %s failed: %v.", u, err)
continue continue

View file

@ -10,7 +10,6 @@ package main
import ( import (
"errors" "errors"
"github.com/gocsaf/csaf/v3/internal/misc"
"net/http" "net/http"
"net/url" "net/url"
"sort" "sort"
@ -217,12 +216,6 @@ func defaults[T any](p *T, def T) T {
// processROLIEFeeds goes through all ROLIE feeds and checks their // processROLIEFeeds goes through all ROLIE feeds and checks their
// integrity and completeness. // integrity and completeness.
func (p *processor) processROLIEFeeds(feeds [][]csaf.Feed) error { func (p *processor) processROLIEFeeds(feeds [][]csaf.Feed) error {
base, err := url.Parse(p.pmdURL)
if err != nil {
return err
}
base.Path = ""
p.badROLIEFeed.use() p.badROLIEFeed.use()
advisories := map[*csaf.Feed][]csaf.AdvisoryFile{} advisories := map[*csaf.Feed][]csaf.AdvisoryFile{}
@ -234,12 +227,11 @@ func (p *processor) processROLIEFeeds(feeds [][]csaf.Feed) error {
if feed.URL == nil { if feed.URL == nil {
continue continue
} }
up, err := url.Parse(string(*feed.URL)) feedBase, err := url.Parse(string(*feed.URL))
if err != nil { if err != nil {
p.badProviderMetadata.error("Invalid URL %s in feed: %v.", *feed.URL, err) p.badProviderMetadata.error("Invalid URL %s in feed: %v.", *feed.URL, err)
continue continue
} }
feedBase := misc.JoinURL(base, up)
feedURL := feedBase.String() feedURL := feedBase.String()
p.checkTLS(feedURL) p.checkTLS(feedURL)
@ -266,13 +258,12 @@ func (p *processor) processROLIEFeeds(feeds [][]csaf.Feed) error {
continue continue
} }
up, err := url.Parse(string(*feed.URL)) feedURL, err := url.Parse(string(*feed.URL))
if err != nil { if err != nil {
p.badProviderMetadata.error("Invalid URL %s in feed: %v.", *feed.URL, err) p.badProviderMetadata.error("Invalid URL %s in feed: %v.", *feed.URL, err)
continue continue
} }
feedURL := misc.JoinURL(base, up)
feedBase, err := util.BaseURL(feedURL) feedBase, err := util.BaseURL(feedURL)
if err != nil { if err != nil {
p.badProviderMetadata.error("Bad base path: %v", err) p.badProviderMetadata.error("Bad base path: %v", err)
@ -292,7 +283,7 @@ func (p *processor) processROLIEFeeds(feeds [][]csaf.Feed) error {
// TODO: Issue a warning if we want check AMBER+ without an // TODO: Issue a warning if we want check AMBER+ without an
// authorizing client. // authorizing client.
if err := p.integrity(files, base.String(), rolieMask, p.badProviderMetadata.add); err != nil { if err := p.integrity(files, rolieMask, p.badProviderMetadata.add); err != nil {
if err != errContinue { if err != errContinue {
return err return err
} }
@ -321,13 +312,12 @@ func (p *processor) processROLIEFeeds(feeds [][]csaf.Feed) error {
continue continue
} }
up, err := url.Parse(string(*feed.URL)) feedBase, err := url.Parse(string(*feed.URL))
if err != nil { if err != nil {
p.badProviderMetadata.error("Invalid URL %s in feed: %v.", *feed.URL, err) p.badProviderMetadata.error("Invalid URL %s in feed: %v.", *feed.URL, err)
continue continue
} }
feedBase := misc.JoinURL(base, up)
makeAbs := makeAbsolute(feedBase) makeAbs := makeAbsolute(feedBase)
label := defaults(feed.TLPLabel, csaf.TLPLabelUnlabeled) label := defaults(feed.TLPLabel, csaf.TLPLabelUnlabeled)

View file

@ -226,18 +226,16 @@ func (d *downloader) download(ctx context.Context, domain string) error {
} }
} }
base, err := url.Parse(lpmd.URL) pmdURL, err := url.Parse(lpmd.URL)
if err != nil { if err != nil {
return fmt.Errorf("invalid URL '%s': %v", lpmd.URL, err) return fmt.Errorf("invalid URL '%s': %v", lpmd.URL, err)
} }
base.Path = ""
expr := util.NewPathEval() expr := util.NewPathEval()
if err := d.loadOpenPGPKeys( if err := d.loadOpenPGPKeys(
client, client,
lpmd.Document, lpmd.Document,
base,
expr, expr,
); err != nil { ); err != nil {
return err return err
@ -247,7 +245,7 @@ func (d *downloader) download(ctx context.Context, domain string) error {
client, client,
expr, expr,
lpmd.Document, lpmd.Document,
base) pmdURL)
// Do we need time range based filtering? // Do we need time range based filtering?
if d.cfg.Range != nil { if d.cfg.Range != nil {
@ -312,7 +310,6 @@ allFiles:
func (d *downloader) loadOpenPGPKeys( func (d *downloader) loadOpenPGPKeys(
client util.Client, client util.Client,
doc any, doc any,
base *url.URL,
expr *util.PathEval, expr *util.PathEval,
) error { ) error {
src, err := expr.Eval("$.public_openpgp_keys", doc) src, err := expr.Eval("$.public_openpgp_keys", doc)
@ -337,7 +334,7 @@ func (d *downloader) loadOpenPGPKeys(
if key.URL == nil { if key.URL == nil {
continue continue
} }
up, err := url.Parse(*key.URL) u, err := url.Parse(*key.URL)
if err != nil { if err != nil {
slog.Warn("Invalid URL", slog.Warn("Invalid URL",
"url", *key.URL, "url", *key.URL,
@ -345,9 +342,7 @@ func (d *downloader) loadOpenPGPKeys(
continue continue
} }
u := base.JoinPath(up.Path).String() res, err := client.Get(u.String())
res, err := client.Get(u)
if err != nil { if err != nil {
slog.Warn( slog.Warn(
"Fetching public OpenPGP key failed", "Fetching public OpenPGP key failed",

View file

@ -12,7 +12,6 @@ import (
"context" "context"
"encoding/csv" "encoding/csv"
"fmt" "fmt"
"github.com/gocsaf/csaf/v3/internal/misc"
"io" "io"
"log/slog" "log/slog"
"net/http" "net/http"
@ -20,6 +19,7 @@ import (
"strings" "strings"
"time" "time"
"github.com/gocsaf/csaf/v3/internal/misc"
"github.com/gocsaf/csaf/v3/util" "github.com/gocsaf/csaf/v3/util"
) )
@ -96,7 +96,7 @@ type AdvisoryFileProcessor struct {
client util.Client client util.Client
expr *util.PathEval expr *util.PathEval
doc any doc any
base *url.URL pmdURL *url.URL
} }
// NewAdvisoryFileProcessor constructs a filename extractor // NewAdvisoryFileProcessor constructs a filename extractor
@ -105,13 +105,13 @@ func NewAdvisoryFileProcessor(
client util.Client, client util.Client,
expr *util.PathEval, expr *util.PathEval,
doc any, doc any,
base *url.URL, pmdURL *url.URL,
) *AdvisoryFileProcessor { ) *AdvisoryFileProcessor {
return &AdvisoryFileProcessor{ return &AdvisoryFileProcessor{
client: client, client: client,
expr: expr, expr: expr,
doc: doc, doc: doc,
base: base, pmdURL: pmdURL,
} }
} }
@ -180,7 +180,7 @@ func (afp *AdvisoryFileProcessor) Process(
// Not found -> fall back to PMD url // Not found -> fall back to PMD url
if empty(dirURLs) { if empty(dirURLs) {
baseURL, err := util.BaseURL(afp.base) baseURL, err := util.BaseURL(afp.pmdURL)
if err != nil { if err != nil {
return err return err
} }
@ -262,8 +262,13 @@ func (afp *AdvisoryFileProcessor) loadChanges(
continue continue
} }
pathURL, err := url.Parse(path)
if err != nil {
return nil, err
}
files = append(files, files = append(files,
DirectoryAdvisoryFile{Path: base.JoinPath(path).String()}) DirectoryAdvisoryFile{Path: misc.JoinURL(base, pathURL).String()})
} }
return files, nil return files, nil
} }
@ -277,12 +282,11 @@ func (afp *AdvisoryFileProcessor) processROLIE(
if feed.URL == nil { if feed.URL == nil {
continue continue
} }
up, err := url.Parse(string(*feed.URL)) feedURL, err := url.Parse(string(*feed.URL))
if err != nil { if err != nil {
slog.Error("Invalid URL in feed", "feed", *feed.URL, "err", err) slog.Error("Invalid URL in feed", "feed", *feed.URL, "err", err)
continue continue
} }
feedURL := misc.JoinURL(afp.base, up)
slog.Info("Got feed URL", "feed", feedURL) slog.Info("Got feed URL", "feed", feedURL)
fb, err := util.BaseURL(feedURL) fb, err := util.BaseURL(feedURL)
@ -290,12 +294,6 @@ func (afp *AdvisoryFileProcessor) processROLIE(
slog.Error("Invalid feed base URL", "url", fb, "err", err) slog.Error("Invalid feed base URL", "url", fb, "err", err)
continue continue
} }
feedBaseURL, err := url.Parse(fb)
if err != nil {
slog.Error("Cannot parse feed base URL", "url", fb, "err", err)
continue
}
feedBaseURL.Path = ""
res, err := afp.client.Get(feedURL.String()) res, err := afp.client.Get(feedURL.String())
if err != nil { if err != nil {
@ -327,7 +325,7 @@ func (afp *AdvisoryFileProcessor) processROLIE(
slog.Error("Invalid URL", "url", u, "err", err) slog.Error("Invalid URL", "url", u, "err", err)
return "" return ""
} }
return misc.JoinURL(feedBaseURL, p).String() return p.String()
} }
rfeed.Entries(func(entry *Entry) { rfeed.Entries(func(entry *Entry) {