File: well_formed_name.go

package info (click to toggle)
golang-github-knqyf263-go-cpe 0.0~git20180327.659663f6-4
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, bullseye, experimental, forky, sid, trixie
  • size: 18,036 kB
  • sloc: sh: 11; makefile: 4
file content (224 lines) | stat: -rw-r--r-- 6,897 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
package common

import (
	"fmt"
	"strings"
	"unicode"

	"github.com/pkg/errors"
)

const (
	AttributePart      = "part"
	AttributeVendor    = "vendor"
	AttributeProduct   = "product"
	AttributeVersion   = "version"
	AttributeUpdate    = "update"
	AttributeEdition   = "edition"
	AttributeLanguage  = "language"
	AttributeSwEdition = "sw_edition"
	AttributeTargetSw  = "target_sw"
	AttributeTargetHw  = "target_hw"
	AttributeOther     = "other"
)

var (
	attributes = []string{AttributePart, AttributeVendor, AttributeProduct, AttributeVersion, AttributeUpdate,
		AttributeEdition, AttributeLanguage, AttributeSwEdition, AttributeTargetSw, AttributeTargetHw, AttributeOther}

	// ErrIllegalAttribute is returned when illegal argument
	ErrIllegalAttribute = errors.New("Illegal attribute")
	// ErrParse is returned when parse error
	ErrParse = errors.New("Parse error")
)

// WellFormedName represents a Well Formed Name, as defined
// in the CPE Specification version 2.3.
//
// @see <a href="http://cpe.mitre.org">cpe.mitre.org</a> for details.
type WellFormedName map[string]interface{}

// NewWellFormedName constructs a new WellFormedName object, with all components set to the default value "ANY".
func NewWellFormedName() WellFormedName {
	wfn := WellFormedName{}
	for _, a := range attributes {
		if a != AttributePart {
			wfn[a], _ = NewLogicalValue("ANY")
		}
	}
	return wfn
}

// Initialize sets each component to the given parameter value.
// If a parameter is null, the component is set to the default value "ANY".
// @param part string representing the part component
// @param vendor string representing the vendor component
// @param product string representing the product component
// @param version string representing the version component
// @param update string representing the update component
// @param edition string representing the edition component
// @param language string representing the language component
// @param sw_edition string representing the sw_edition component
// @param target_sw string representing the target_sw component
// @param target_hw string representing the target_hw component
// @param other string representing the other component
func (wfn WellFormedName) Initialize(part, vendor, product, version, update, edition, language, swEdition, targetSw, targetHw, other interface{}) {
	wfn[AttributePart] = part
	wfn[AttributeVendor] = vendor
	wfn[AttributeProduct] = product
	wfn[AttributeVersion] = version
	wfn[AttributeUpdate] = update
	wfn[AttributeEdition] = edition
	wfn[AttributeLanguage] = language
	wfn[AttributeSwEdition] = swEdition
	wfn[AttributeTargetSw] = targetSw
	wfn[AttributeTargetHw] = targetHw
	wfn[AttributeOther] = other
}

// Get gets attribute
// @param attribute String representing the component value to get
// @return the String value of the given component, or default value "ANY"
// if the component does not exist
func (wfn WellFormedName) Get(attribute string) interface{} {
	if v, ok := wfn[attribute]; ok {
		return v
	}
	any, _ := NewLogicalValue("ANY")
	return any
}

// Set sets the given attribute to value, if the attribute is in the list of permissible components
// @param attribute String representing the component to set
// @param value Object representing the value of the given component
func (wfn WellFormedName) Set(attribute string, value interface{}) (err error) {
	if valid := IsValidAttribute(attribute); !valid {
		return ErrIllegalAttribute
	}

	if value == nil {
		wfn[attribute], _ = NewLogicalValue("ANY")
		return nil
	}

	if _, ok := value.(LogicalValue); ok {
		if attribute == AttributePart {
			return errors.Wrap(ErrIllegalAttribute, "part component cannot be a logical value")
		}
		wfn[attribute] = value
		return nil
	}

	svalue, ok := value.(string)
	if !ok {
		return errors.Wrap(ErrIllegalAttribute, "value must be a logical value or string")
	}

	if err = ValidateStringValue(svalue); err != nil {
		return errors.Wrap(err, "Failed to validate a value")
	}

	// part must be a, o, or h
	if attribute == AttributePart {
		if svalue != "a" && svalue != "o" && svalue != "h" {
			return errors.Wrapf(ErrParse, "part component must be one of the following: 'a', 'o', 'h': %s", svalue)
		}
	}

	// should be good to go
	wfn[attribute] = value

	return nil
}

// GetString gets attribute as string
// @param attribute String representing the component value to get
// @return the String value of the given component, or default value "ANY"
// if the component does not exist
func (wfn WellFormedName) GetString(attribute string) string {
	return fmt.Sprintf("%s", wfn.Get(attribute))
}

// String returns string representation of the WellFormedName
func (wfn WellFormedName) String() string {
	s := "wfn:["
	for _, attr := range attributes {
		s += fmt.Sprintf("%s=", attr)
		o := wfn.Get(attr)
		if lv, ok := o.(LogicalValue); ok {
			s += fmt.Sprintf("%s, ", lv)
		} else {
			s += fmt.Sprintf("\"%s\", ", o)
		}
	}
	s = strings.TrimSpace(s)
	s = strings.TrimRight(s, ",")
	s += "]"
	return s
}

// IsValidAttribute validates an attribute name
func IsValidAttribute(attribute string) (valid bool) {
	for _, a := range attributes {
		if a == attribute {
			valid = true
		}
	}
	return valid
}

// ValidateStringValue validates an string value
func ValidateStringValue(svalue string) (err error) {
	// svalue has more than one unquoted star
	if strings.HasPrefix(svalue, "**") || strings.HasSuffix(svalue, "**") {
		return errors.Wrapf(ErrParse, "component cannot contain more than one * in sequence: %s", svalue)
	}

	prev := ' ' // dummy value
	for i, r := range svalue {
		// check for printable characters - no control characters
		if !unicode.IsPrint(r) {
			return errors.Wrapf(ErrParse, "encountered non printable character in: %s", svalue)
		}
		// svalue has whitespace
		if unicode.IsSpace(r) {
			return errors.Wrapf(ErrParse, "component cannot contain whitespace:: %s", svalue)
		}
		if unicode.IsPunct(r) && prev != '\\' && r != '\\' {
			// svalue has an unquoted *
			if r == '*' && (i != 0 && i != len(svalue)-1) {
				return errors.Wrapf(ErrParse, "component cannot contain embedded *: %s", svalue)
			}

			if r != '*' && r != '?' && r != '_' {
				// svalue has unquoted punctuation embedded
				return errors.Wrapf(ErrParse, "component cannot contain unquoted punctuation: %s", svalue)
			}
		}
		prev = r
	}

	if strings.Contains(svalue, "?") {
		if svalue == "?" {
			// single ? is valid
			return nil
		}

		s := strings.Trim(svalue, "?")
		if ContainsQuestions(s) {
			return errors.Wrapf(ErrParse, "component cannot contain embedded ?: %s", svalue)
		}
	}

	// single asterisk is not allowed
	if svalue == "*" {
		return errors.Wrapf(ErrParse, "component cannot be a single *: %s", svalue)
	}

	// quoted hyphen not allowed by itself
	if svalue == `\-` {
		return errors.Wrapf(ErrParse, "component cannot be quoted hyphen: %s", svalue)
	}

	return nil
}