Skip to content

Commit 45f96ee

Browse files
committed
Added packageUrl.js, created middleware function utilizing this package and custom code to syntatically validate PURLs
1 parent 452a4db commit 45f96ee

File tree

3 files changed

+86
-4
lines changed

3 files changed

+86
-4
lines changed

package-lock.json

Lines changed: 12 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,10 @@
2727
"standard": "^16.0.3"
2828
},
2929
"dependencies": {
30-
"bson": "^6.10.1",
3130
"ajv": "^8.6.2",
3231
"ajv-formats": "^2.1.1",
3332
"argon2": "^0.41.1",
33+
"bson": "^6.10.1",
3434
"config": "^3.3.6",
3535
"cors": "^2.8.5",
3636
"crypto-random-string": "^3.3.1",
@@ -50,6 +50,7 @@
5050
"mongoose-aggregate-paginate-v2": "1.0.6",
5151
"morgan": "^1.9.1",
5252
"node-dev": "^7.4.3",
53+
"packageurl-js": "^2.0.1",
5354
"prompt-sync": "^4.2.0",
5455
"replace-in-file": "6.3.5",
5556
"replace-json-property": "^1.8.0",
@@ -60,7 +61,11 @@
6061
"winston": "^3.2.1",
6162
"yamljs": "^0.3.0"
6263
},
63-
"overrides": { "mongo-cursor-pagination": { "bson": "^6.10.1" } },
64+
"overrides": {
65+
"mongo-cursor-pagination": {
66+
"bson": "^6.10.1"
67+
}
68+
},
6469
"apidoc": {
6570
"name": "CVE-Services",
6671
"version": "0.0.0",
@@ -103,4 +108,4 @@
103108
"test:coverage-html": "NODE_ENV=test nyc --reporter=html mocha src/* --recursive --exit || true",
104109
"test:scripts": "NODE_ENV=development node-dev src/scripts/templateScript.js"
105110
}
106-
}
111+
}

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

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
const { PackageURL } = require('packageurl-js')
12
const { body, validationResult } = require('express-validator')
23
const errors = require('./error')
34
const error = new errors.CveControllerError()
@@ -184,6 +185,69 @@ function validateCveAdpContainerJsonSchema (req, res, next) {
184185
next()
185186
}
186187

188+
// PURL validator middleware
189+
function validatePURL (pURLIndex) {
190+
return body(pURLIndex).optional({ nullable: true }).bail().custom((affected) => {
191+
for (const affObj of affected) {
192+
const purlStr = affObj.packageURL
193+
let purlObj
194+
let parsedPurlArray
195+
// Passes first validation check if PackageURL can build a PURL from the string
196+
try {
197+
// PURL class from PackageURL
198+
purlObj = PackageURL.fromString(purlStr)
199+
// PURL string broken up by component and store in array. Used for additional validation
200+
parsedPurlArray = PackageURL.parseString(purlStr)
201+
console.log(purlObj)
202+
console.log(parsedPurlArray)
203+
// console.log(PackageURL.fromString(purlObj.toString()))
204+
} catch (e) {
205+
throw new Error(e.message)
206+
}
207+
208+
// PURL's with versions are not allowed
209+
if (purlObj.version !== undefined) {
210+
throw new Error('The PURL version component is currently not supported by the CVE schema')
211+
}
212+
213+
// PackageURL does not properly account for certain Subpath situations
214+
// so adding additional validation to account for them
215+
if (purlObj.subpath !== undefined) {
216+
// Checks if any subpaths contain invalid characters
217+
// Subpaths cannot be '.' or '..'
218+
const parsedSubpaths = subpathHelper(parsedPurlArray[5])
219+
220+
console.log(parsedSubpaths)
221+
222+
if (parsedSubpaths.includes('..') || parsedSubpaths.includes('.')) {
223+
throw new Error("Subpaths cannot be '.' or '..' ")
224+
}
225+
226+
if (parsedSubpaths.includes('')) {
227+
throw new Error("Subpaths cannot be empty or contain only a '/' ")
228+
}
229+
}
230+
}
231+
return true
232+
}
233+
)
234+
}
235+
236+
// Parses subpaths into array, stripping leading and trailing '/'
237+
function subpathHelper (subpathStr) {
238+
// remove leading and trailing '/'s
239+
if (subpathStr[0] === '/') {
240+
subpathStr = subpathStr.slice(1)
241+
}
242+
243+
if (subpathStr[subpathStr.length - 1] === '/') {
244+
subpathStr = subpathStr.slice(0, subpathStr.length - 1)
245+
}
246+
247+
const parsedSubpaths = subpathStr.split('/')
248+
return parsedSubpaths
249+
}
250+
187251
module.exports = {
188252
parseGetParams,
189253
parsePostParams,
@@ -195,5 +259,6 @@ module.exports = {
195259
validateDescription,
196260
validateRejectBody,
197261
validateDatePublic,
198-
datePublicHelper
262+
datePublicHelper,
263+
validatePURL
199264
}

0 commit comments

Comments
 (0)