package cpe import ( "encoding/json" "errors" "fmt" "strings" ) // Common Platform Enumeration binding. type Binding struct { Part Part // Part attribute (NISTIR7695 5.3.3.1). Vendor AvString // Vendor attribute (NISTIR7695 5.3.3.2). Product AvString // Product attribute (NISTIR7695 5.3.3.3). Version AvString // Version attribute (NISTIR7695 5.3.3.4). Update AvString // Update attribute (NISTIR7695 5.3.3.5). Edition AvString // Edition attribute (NISTIR7695 5.3.3.6). SwEdition AvString // Software edition attribute (NISTIR7695 5.3.3.7). TargetSw AvString // Target software attribute (NISTIR7695 5.3.3.8). TargetHw AvString // Target hardware attribute (NISTIR7695 5.3.3.9). Lang AvString // Language attribute (NISTIR7695 5.3.3.10). Other AvString // Other attribute (NISTIR7695 5.3.3.11). } // cpe 2.3 formatted string prefix var cpe23Prefix = "cpe:2.3:" // missing prefix error var missingPrefix = errors.New("missing CPE 2.3 prefix") // Create CPE 2.3 binding from formatted string. func NewBinding(s string) (Binding, error) { // check prefix if s[0:len(cpe23Prefix)] != cpe23Prefix { return Binding{}, missingPrefix } // tokenize string, check for error toks, err := tokenize([]byte(s[len(cpe23Prefix):])) if err != nil { return Binding{}, err } // check token count if len(toks) != 11 { err = fmt.Errorf("invalid attribute count: %d != 11", len(toks)) return Binding{}, err } // create part part, err := newPart(toks[0]) if err != nil { return Binding{}, err } // parse tokens into strings strs := make([]AvString, len(toks) - 1) for i, t := range(toks[1:]) { if strs[i], err = newAvString(t); err != nil { return Binding{}, err } } // build and return result return Binding { Part: part, Vendor: strs[0], Product: strs[1], Version: strs[2], Update: strs[3], Edition: strs[4], Lang: strs[5], SwEdition: strs[6], TargetSw: strs[7], TargetHw: strs[8], Other: strs[9], }, nil } func (v Binding) String() string { return cpe23Prefix + strings.Join([]string { v.Part.String(), v.Vendor.String(), v.Product.String(), v.Version.String(), v.Update.String(), v.Edition.String(), v.Lang.String(), v.SwEdition.String(), v.TargetSw.String(), v.TargetHw.String(), v.Other.String(), }, ":") } // Unmarshal CPE formatted string from JSON string. func (me *Binding) UnmarshalJSON(b []byte) error { // decode json string var s string if err := json.Unmarshal(b, &s); err != nil { return err } // create binding binding, err := NewBinding(s) if err != nil { return err } // save result, return success *me = binding return nil } // Marshal CPE formatted string as JSON string. func (v Binding) MarshalJSON() ([]byte, error) { return json.Marshal(v.String()) }