Skip to content

Commit 0079738

Browse files
authored
Merge pull request #1560 from CVEProject/jd-5.2.0-schema
Resolves issues #1554, #1555, #1556, #1557 Various purl validation fixes
2 parents cda24fc + 2917ab8 commit 0079738

File tree

2 files changed

+76
-11
lines changed

2 files changed

+76
-11
lines changed

src/controller/cve.controller/cve.middleware.js

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -197,9 +197,9 @@ function purlValidateHelper (affected) {
197197
for (const affObj of affected) {
198198
const purlStr = affObj.packageURL
199199

200-
// If no PURL string provided, skip validation
200+
// If no PURL string provided, skip validation and continue through loop
201201
if (!purlStr) {
202-
return true
202+
continue
203203
}
204204
let purlObj
205205
let parsedPurlArray
@@ -216,22 +216,48 @@ function purlValidateHelper (affected) {
216216

217217
// PURL's with versions are not allowed
218218
if (purlObj.version !== undefined) {
219-
throw new Error('The PURL version component is currently not supported by the CVE schema: "' + purlStr + '"')
219+
throw new Error('The PURL version component is currently not supported by the CVE schema: ' + purlStr)
220+
}
221+
222+
// Handle qualifier cases
223+
if (purlObj.qualifiers !== undefined) {
224+
// Check for versions within qualifiers
225+
if (Object.keys(purlObj.qualifiers).includes('vers')) {
226+
throw new Error('PURL versions are currently not supported by the CVE schema: ' + purlStr)
227+
}
228+
}
229+
230+
if (parsedPurlArray[4] !== undefined) {
231+
// Check for qualifier with key but no value
232+
if ((Array.from(parsedPurlArray[4].values()).includes(''))) {
233+
throw new Error('Qualifier keys must have a value: ' + purlStr)
234+
}
235+
}
236+
237+
// PackageURL does not properly prevent encoded ':', so check for that here
238+
const encColon = /%3a/i
239+
if (encColon.test(purlStr)) {
240+
throw new Error('Percent-encoded colons are not allowed in a PURL: ' + purlStr)
220241
}
221242

222243
// PackageURL does not properly account for certain Subpath situations
223244
// so adding additional validation to account for them
245+
// Handles PURLs that include a # but no subpath
246+
if (purlObj.subpath === undefined && purlStr.includes('#')) {
247+
throw new Error('Subpaths cannot be empty or contain only a /: ' + purlStr)
248+
}
249+
224250
if (purlObj.subpath !== undefined) {
225251
// Checks if any subpaths contain invalid characters
226252
// Subpaths cannot be '.' or '..'
227253
const parsedSubpaths = subpathHelper(parsedPurlArray[5])
228254

229255
if (parsedSubpaths.includes('..') || parsedSubpaths.includes('.')) {
230-
throw new Error('Subpaths cannot be "." or "..": "' + purlStr + '"')
256+
throw new Error('Subpaths cannot be "." or "..": ' + purlStr)
231257
}
232258

233259
if (parsedSubpaths.includes('')) {
234-
throw new Error('Subpaths cannot be empty or contain only a "/": "' + purlStr + '"')
260+
throw new Error('Subpaths cannot be empty or contain only a /: ' + purlStr)
235261
}
236262
}
237263
}

test/unit-tests/cve/validatePurlTest.js

Lines changed: 45 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,11 @@ const PurlRecordVersion = [
4848
}
4949
]
5050

51+
const RecordQualifierVersionPurl = [
52+
{
53+
packageURL: 'pkg:pypi/django?vers=vers:pypi%2F%3E%3D1.11.0%7C%21%3D1.11.1%7C%3C2.0.0'
54+
}
55+
]
5156
const PurlRecordEmptySubpath = [
5257
{
5358
packageURL: 'pkg:npm/foo/bar?q=1&s=2#test//'
@@ -72,6 +77,12 @@ const PurlRecordOnlySinglePeriodSubpath = [
7277
}
7378
]
7479

80+
const PurlRecordPoundSymbolEmpty = [
81+
{
82+
packageURL: 'pkg:npm/foo/bar?q=1&s=2#'
83+
}
84+
]
85+
7586
const MultipleRecordsOneInvalid = [
7687
{
7788
packageURL: 'pkg:npm/foo/bar?q=1&s=2#./'
@@ -93,12 +104,24 @@ const MultipleRecordsOneInvalid = [
93104
}
94105
]
95106

107+
const PurlEncodedColonRecord = [
108+
{
109+
packageURL: 'pkg:pypi/django#%3A'
110+
}
111+
]
112+
96113
const RecordNoPurl = [
97114
{
98115
test: 'testing String'
99116
}
100117
]
101118

119+
const PurlQualifierKeyNoValueRecord = [
120+
{
121+
packageURL: 'pkg:npm/package-name?qualifier&test=value'
122+
}
123+
]
124+
102125
describe('Testing validatePURL middleware', () => {
103126
context('Positive Tests', () => {
104127
it('Should validate a correctly formatted PURL ', () => {
@@ -123,27 +146,43 @@ describe('Testing validatePURL middleware', () => {
123146
})
124147

125148
it('Should fail to validate a PURL object with a version component ', () => {
126-
expect(() => purlValidateHelper(PurlRecordVersion)).to.throw('The PURL version component is currently not supported by the CVE schema: "' + PurlRecordVersion[0].packageURL + '"')
149+
expect(() => purlValidateHelper(PurlRecordVersion)).to.throw('The PURL version component is currently not supported by the CVE schema: ' + PurlRecordVersion[0].packageURL)
127150
})
128151

129152
it('Should fail to validate a PURL object with one non-empty subpath and at least one empty subpath ', () => {
130-
expect(() => purlValidateHelper(PurlRecordEmptySubpath)).to.throw('Subpaths cannot be empty or contain only a "/": "' + PurlRecordEmptySubpath[0].packageURL + '"')
153+
expect(() => purlValidateHelper(PurlRecordEmptySubpath)).to.throw('Subpaths cannot be empty or contain only a /: ' + PurlRecordEmptySubpath[0].packageURL)
131154
})
132155

133156
it('Should fail to validate a PURL object with a subpath containing only a "/" ', () => {
134-
expect(() => purlValidateHelper(PurlRecordOnlySlashSubpath)).to.throw('Subpaths cannot be empty or contain only a "/": "' + PurlRecordOnlySlashSubpath[0].packageURL + '"')
157+
expect(() => purlValidateHelper(PurlRecordOnlySlashSubpath)).to.throw('Subpaths cannot be empty or contain only a /: ' + PurlRecordOnlySlashSubpath[0].packageURL)
135158
})
136159

137160
it('Should fail to validate a PURL object with a subpath equal to "." ', () => {
138-
expect(() => purlValidateHelper(PurlRecordOnlySinglePeriodSubpath)).to.throw('Subpaths cannot be "." or "..": "' + PurlRecordOnlySinglePeriodSubpath[0].packageURL + '"')
161+
expect(() => purlValidateHelper(PurlRecordOnlySinglePeriodSubpath)).to.throw('Subpaths cannot be "." or "..": ' + PurlRecordOnlySinglePeriodSubpath[0].packageURL)
139162
})
140163

141164
it('Should fail to validate a PURL object with a subpath equal to ".." ', () => {
142-
expect(() => purlValidateHelper(PurlRecordOnlyDoublePeriodSubpath)).to.throw('Subpaths cannot be "." or "..": "' + PurlRecordOnlyDoublePeriodSubpath[0].packageURL + '"')
165+
expect(() => purlValidateHelper(PurlRecordOnlyDoublePeriodSubpath)).to.throw('Subpaths cannot be "." or "..": ' + PurlRecordOnlyDoublePeriodSubpath[0].packageURL)
166+
})
167+
168+
it('Should fail to validate a PURL object with a # symbol but no subpath ', () => {
169+
expect(() => purlValidateHelper(PurlRecordPoundSymbolEmpty)).to.throw('Subpaths cannot be empty or contain only a /: ' + PurlRecordPoundSymbolEmpty[0].packageURL)
143170
})
144171

145172
it('Should fail to validate when at least one PURL object in an array is invalid ', () => {
146-
expect(() => purlValidateHelper(MultipleRecordsOneInvalid)).to.throw('Subpaths cannot be "." or "..": "' + PurlRecordOnlySinglePeriodSubpath[0].packageURL + '"')
173+
expect(() => purlValidateHelper(MultipleRecordsOneInvalid)).to.throw('Subpaths cannot be "." or "..": ' + PurlRecordOnlySinglePeriodSubpath[0].packageURL)
174+
})
175+
176+
it('Should fail to validate when a version is passed in the qualifier component ', () => {
177+
expect(() => purlValidateHelper(RecordQualifierVersionPurl)).to.throw('PURL versions are currently not supported by the CVE schema: ' + RecordQualifierVersionPurl[0].packageURL)
178+
})
179+
180+
it('Should fail to validate when a qualifier has a key and no value ', () => {
181+
expect(() => purlValidateHelper(PurlQualifierKeyNoValueRecord)).to.throw('Qualifier keys must have a value: ' + PurlQualifierKeyNoValueRecord[0].packageURL)
182+
})
183+
184+
it('Should fail to validate when a PURL contain an encoded colon ', () => {
185+
expect(() => purlValidateHelper(PurlEncodedColonRecord)).to.throw('Percent-encoded colons are not allowed in a PURL: ' + PurlEncodedColonRecord[0].packageURL)
147186
})
148187
})
149188
})

0 commit comments

Comments
 (0)