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

Fixed problem with JSON decoding in loading PMD

This commit is contained in:
Sascha L. Teichmann 2023-05-15 10:43:16 +02:00
parent 2e968b197d
commit 018a1814f0

View file

@ -115,21 +115,13 @@ func (pmdl *ProviderMetadataLoader) Load(domain string) *LoadedProviderMetadata
// Check direct path // Check direct path
if strings.HasPrefix(domain, "https://") { if strings.HasPrefix(domain, "https://") {
lpmd, err := pmdl.loadFromURL(domain) return pmdl.loadFromURL(domain)
if err != nil {
lpmd = new(LoadedProviderMetadata)
lpmd.Messages.Add(HTTPFailed, err.Error())
}
return lpmd
} }
// First try the well-known path. // First try the well-known path.
wellknownURL := "https://" + domain + "/.well-known/csaf/provider-metadata.json" wellknownURL := "https://" + domain + "/.well-known/csaf/provider-metadata.json"
wellknownResult, err := pmdl.loadFromURL(wellknownURL) wellknownResult := pmdl.loadFromURL(wellknownURL)
if err != nil {
pmdl.messages.Add(HTTPFailed, err.Error())
}
// Valid provider metadata under well-known. // Valid provider metadata under well-known.
var wellknownGood *LoadedProviderMetadata var wellknownGood *LoadedProviderMetadata
@ -203,16 +195,7 @@ func (pmdl *ProviderMetadataLoader) Load(domain string) *LoadedProviderMetadata
// Last resort: fall back to DNS. // Last resort: fall back to DNS.
dnsURL := "https://csaf.data.security." + domain dnsURL := "https://csaf.data.security." + domain
return pmdl.loadFromURL(dnsURL)
dnsResult, err := pmdl.loadFromURL(dnsURL)
if err != nil {
dnsResult = new(LoadedProviderMetadata)
pmdl.messages.Add(
HTTPFailed,
err.Error())
}
dnsResult.Messages.AppendUnique(pmdl.messages)
return dnsResult
} }
// loadFromSecurity loads the PMDs mentioned in the security.txt. // loadFromSecurity loads the PMDs mentioned in the security.txt.
@ -250,12 +233,10 @@ func (pmdl *ProviderMetadataLoader) loadFromSecurity(path string) []*LoadedProvi
// Load the URLs // Load the URLs
nextURL: nextURL:
for _, url := range urls { for _, url := range urls {
lpmd, err := pmdl.loadFromURL(url) lpmd := pmdl.loadFromURL(url)
// If loading failed note it down. // If loading failed note it down.
if err != nil { if !lpmd.Valid() {
pmdl.messages.Add( pmdl.messages.AppendUnique(lpmd.Messages)
HTTPFailed,
fmt.Sprintf("Loading %q failed: %v", url, err))
continue continue
} }
// Check for duplicates // Check for duplicates
@ -271,14 +252,22 @@ nextURL:
} }
// loadFromURL loads a provider metadata from a given URL. // loadFromURL loads a provider metadata from a given URL.
func (pmdl *ProviderMetadataLoader) loadFromURL(path string) (*LoadedProviderMetadata, error) { func (pmdl *ProviderMetadataLoader) loadFromURL(path string) *LoadedProviderMetadata {
result := LoadedProviderMetadata{URL: path}
res, err := pmdl.client.Get(path) res, err := pmdl.client.Get(path)
if err != nil { if err != nil {
return nil, fmt.Errorf("fetching %q failed: %v", path, err) result.Messages.Add(
HTTPFailed,
fmt.Sprintf("fetching %q failed: %v", path, err))
return &result
} }
if res.StatusCode != http.StatusOK { if res.StatusCode != http.StatusOK {
return nil, fmt.Errorf("fetching %q failed: %s (%d)", path, res.Status, res.StatusCode) result.Messages.Add(
HTTPFailed,
fmt.Sprintf("fetching %q failed: %s (%d)", path, res.Status, res.StatusCode))
return &result
} }
// TODO: Check for application/json and log it. // TODO: Check for application/json and log it.
@ -288,14 +277,15 @@ func (pmdl *ProviderMetadataLoader) loadFromURL(path string) (*LoadedProviderMet
// Calculate checksum for later comparison. // Calculate checksum for later comparison.
hash := sha256.New() hash := sha256.New()
result := LoadedProviderMetadata{URL: path}
tee := io.TeeReader(res.Body, hash) tee := io.TeeReader(res.Body, hash)
var doc any var doc any
if err := json.NewDecoder(tee).Decode(&doc); err != nil { if err := json.NewDecoder(tee).Decode(&doc); err != nil {
return nil, fmt.Errorf("JSON decoding failed: %w", err) result.Messages.Add(
JSONDecodingFailed,
fmt.Sprintf("JSON decoding failed: %v", err))
return &result
} }
// Before checking the err lets check if we had the same // Before checking the err lets check if we had the same
@ -306,17 +296,16 @@ func (pmdl *ProviderMetadataLoader) loadFromURL(path string) (*LoadedProviderMet
// If we already have loaded it return the cached result. // If we already have loaded it return the cached result.
if r := pmdl.already[key]; r != nil { if r := pmdl.already[key]; r != nil {
return r, nil return r
} }
// write it back as loaded // write it back as loaded
switch errors, err := ValidateProviderMetadata(doc); { switch errors, err := ValidateProviderMetadata(doc); {
case err != nil: case err != nil:
result.Messages = []ProviderMetadataLoadMessage{{ result.Messages.Add(
Type: SchemaValidationFailed, SchemaValidationFailed,
Message: fmt.Sprintf("%s: Validating against JSON schema failed: %v", path, err), fmt.Sprintf("%s: Validating against JSON schema failed: %v", path, err))
}}
case len(errors) > 0: case len(errors) > 0:
result.Messages = []ProviderMetadataLoadMessage{{ result.Messages = []ProviderMetadataLoadMessage{{
@ -324,10 +313,9 @@ func (pmdl *ProviderMetadataLoader) loadFromURL(path string) (*LoadedProviderMet
Message: fmt.Sprintf("%s: Validating against JSON schema failed: %v", path, err), Message: fmt.Sprintf("%s: Validating against JSON schema failed: %v", path, err),
}} }}
for _, msg := range errors { for _, msg := range errors {
result.Messages = append(result.Messages, ProviderMetadataLoadMessage{ result.Messages.Add(
Type: SchemaValidationFailedDetail, SchemaValidationFailedDetail,
Message: strings.ReplaceAll(msg, `%`, `%%`), strings.ReplaceAll(msg, `%`, `%%`))
})
} }
default: default:
// Only store in result if validation passed. // Only store in result if validation passed.
@ -336,5 +324,5 @@ func (pmdl *ProviderMetadataLoader) loadFromURL(path string) (*LoadedProviderMet
} }
pmdl.already[key] = &result pmdl.already[key] = &result
return &result, nil return &result
} }