diff --git a/functions/src/CVE/index.ts b/functions/src/CVE/index.ts index 5460c38..d63b58e 100644 --- a/functions/src/CVE/index.ts +++ b/functions/src/CVE/index.ts @@ -19,54 +19,48 @@ export const getCVE = functions.https.onRequest((request, response) => { if (bulletinID) { if (!checks.checkBulletinIDValidity(bulletinID)) { response.status(400).send('Bulletin ID is malformed.'); - }else{ + } else { if (v1 && v2) { if (!checks.checkVersionIDValidity(v1) || !checks.checkVersionIDValidity(v2)) { response.status(400).send('Version ID is malformed.'); - }else{ + } else { version1And2VulDifference(String(bulletinID), String(v1), String(v2), response); } - }else{ + } else { getCvesWithBulletinID(String(bulletinID), response); } } - } - else if (splID) { + } else if (splID) { if (!checks.checkSPLValidity(splID)) { response.status(400).send('SPL ID is malformed.'); - }else{ + } else { getCvesWithSplID(String(splID), response); } - } - else if (splStart) { + } else if (splStart) { if (!checks.checkSPLValidity(splStart)) { response.status(400).send('SPL ID is malformed.'); - }else{ + } else { getCVEsBeforeSPL(String(splStart), response); } - } - else if (cveID) { + } else if (cveID) { if (!checks.checkCVEValidity(cveID)) { response.status(400).send('CVE ID is malformed.'); - }else{ + } else { getCveWithCveID(String(cveID), response); } - } - else if (spl1 && spl2) { + } else if (spl1 && spl2) { if (!checks.checkSPLValidity(spl1) || !checks.checkSPLValidity(spl2)) { response.status(400).send('SPL ID is malformed.'); - }else{ + } else { getChangesBetweenSPLs(String(spl1), String(spl2), response); } - } - else if (androidVersion) { + } else if (androidVersion) { if (!checks.checkAndroidVersionValidity(androidVersion)) { response.status(400).send('Android Version ID is malformed.'); - }else{ + } else { getCvesWithAndroidVersion(String(androidVersion), response); } - } - else{ + } else { response.status(400).send('No valid parameters specified. Please specify a bulletin/spl/cve/android version.'); } }); @@ -87,9 +81,9 @@ function getCvesWithBulletinID(id: string, res: any) { } res.send(result); }).catch(error => { - if(error instanceof NotFoundError){ + if (error instanceof NotFoundError) { res.status(404).send(error.message); - }else{ + } else { res.status(500).send('error getting CVEs for bulletinID:' + error); } }); @@ -111,15 +105,15 @@ function getCvesWithSplID(id: string, res: any) { } res.send(result); }).catch(error => { - if(error instanceof NotFoundError){ + if (error instanceof NotFoundError) { res.status(404).send(error.message); - }else{ + } else { res.status(500).send('error getting CVEs for SPL:' + error); } }); } -function getCVEsBeforeSPL(id: string, res: any){ +function getCVEsBeforeSPL(id: string, res: any) { var db = admin.database(); var ref = db.ref('/CVEs'); const getCVEsPromise = ref.once('value'); @@ -142,9 +136,9 @@ function getCVEsBeforeSPL(id: string, res: any){ } res.send(result); }).catch(error => { - if(error instanceof NotFoundError){ + if (error instanceof NotFoundError) { res.status(404).send(error.message); - }else{ + } else { res.status(500).send('error getting CVEs with starting SPL:' + error); } }); @@ -153,28 +147,29 @@ function getCVEsBeforeSPL(id: string, res: any){ function version1And2VulDifference(bulletin: string, version1: string, version2: string, res: any) { const db = admin.database(); const ref = db.ref('/CVE_History'); - const wholeVersion1 = bulletin + ':' + version1; + const wholeVersion1 = bulletin + ':' + version1; //key is ASB:Version const wholeVersion2 = bulletin + ':' + version2; const version1And2Vul = ref.once('value'); const version1And2FinalSet = version1And2Vul.then((snapshot) => { const cves = snapshot.val(); - const cves1 = Enumerable.from(cves) + const cves1 = Enumerable.from(cves) //get all cves of first version .where(function (obj) { return obj.value[wholeVersion1] !== undefined }) .select(function (obj) { return obj.value[wholeVersion1] }) .toArray(); if (cves1.length === 0) { throw new NotFoundError('There are no CVEs associated with this bulletin ID and version in the database.'); } - const cves2 = Enumerable.from(cves) + const cves2 = Enumerable.from(cves) //get all cves of second version .where(function (obj) { return obj.value[wholeVersion2] !== undefined }) .select(function (obj) { return obj.value[wholeVersion2] }) .toArray(); if (cves2.length === 0) { throw new NotFoundError('There are no CVEs associated with this bulletin ID and version in the database.'); } - const cves1Set = createSet(cves1); + const cves1Set = createSet(cves1); //create sets from arrays of cves const cves2Set = createSet(cves2); const cvesFinal = symmetricDifferenceBetweenSets(cves1Set, cves2Set); + //find the difference between the two -> added or deleted cves const overlappingCVEs = intersectionBetweenSets(cves1Set, cves2Set); @@ -183,6 +178,7 @@ function version1And2VulDifference(bulletin: string, version1: string, version2: for (const element of overlappingCVEs) { if (!deepEqual(cves1Map.get(element), cves2Map.get(element))) { + //if there has been any chnage to cve add to list cvesFinal.add(element); } } @@ -201,12 +197,12 @@ function version1And2VulDifference(bulletin: string, version1: string, version2: } const result = { 'CVEs': cveList }; res.send(result); - }).catch(error => { - if(error instanceof NotFoundError){ + }).catch(error => { + if (error instanceof NotFoundError) { res.status(404).send(error.message); - }else{ + } else { res.status(500).send('Error getting CVEs for bulletin between v1 and v2: ' + error); - } + } }); } @@ -245,7 +241,7 @@ function intersectionBetweenSets(setA: any, setB: any): Set { function getCveWithCveID(id: any, res: any) { const db = admin.database(); const ref = db.ref('/CVEs'); - + const getCVEsPromise = ref.orderByKey().equalTo(id).once('value'); getCVEsPromise.then((snapshot) => { const cveData = snapshot.val(); @@ -254,9 +250,9 @@ function getCveWithCveID(id: any, res: any) { } res.send(cveData[id]); }).catch(error => { - if(error instanceof NotFoundError){ + if (error instanceof NotFoundError) { res.status(404).send(error.message); - }else{ + } else { res.status(500).send('error getting details for CVEID:' + error); } }); @@ -302,9 +298,9 @@ function getChangesBetweenSPLs(id1: string, id2: string, res: any) { const cvesBetweenSpls = { CVEs: cveList }; res.send(cvesBetweenSpls); }).catch(error => { - if(error instanceof NotFoundError){ + if (error instanceof NotFoundError) { res.status(404).send(error.message); - }else{ + } else { res.status(500).send('error getting CVEs between SPLs: ' + error) } }); @@ -335,12 +331,12 @@ function getCvesWithAndroidVersion(version: string, res: any) { } res.send({ CVEs: cveList }); }).catch(error => { - if(error instanceof NotFoundError){ + if (error instanceof NotFoundError) { res.status(404).send(error.message); - }else{ + } else { res.status(500).send('error getting CVEs for AndroidVersion: ' + error); } }); } -class NotFoundError extends Error {} \ No newline at end of file +class NotFoundError extends Error { } \ No newline at end of file diff --git a/functions/src/errorChecks.ts b/functions/src/errorChecks.ts index c0ff4f8..abe9cca 100644 --- a/functions/src/errorChecks.ts +++ b/functions/src/errorChecks.ts @@ -1,3 +1,5 @@ +//This file checks if the query parameters are formatted correctly + export function checkCVEValidity(ID: any): boolean { const regex = /^CVE-\d{4}-\d{3,7}$/; if (!regex.test(ID)) { diff --git a/functions/src/scripts/README.md b/functions/src/scripts/README.md index 0acac8c..5494bc6 100644 --- a/functions/src/scripts/README.md +++ b/functions/src/scripts/README.md @@ -16,7 +16,7 @@ 4) Run the command: ts-node --project ../../tsconfig.json scriptConverter.ts --inputPath 5)NOTE: You are in the scripts folder of step95-2020/functions/src. The input path should be a JSON representation of the bulletin data. -6) If the script is successful, the console should print that all seven trees have been uploaded. You should see the new data in the realtime database UI. +6) If the script is successful, the console should print that all trees have been uploaded. You should see the new data in the realtime database UI. ## To Run on the UI 1) Navigate to step95-2020.web.app and log in as admin to home page diff --git a/functions/src/scripts/cleanupData.ts b/functions/src/scripts/cleanupData.ts index 2f26c86..e5c75c4 100644 --- a/functions/src/scripts/cleanupData.ts +++ b/functions/src/scripts/cleanupData.ts @@ -1,4 +1,5 @@ export function replacePeriodsWithUnderscores(source: any): void { + //keys in RTDB cannot have periods if (source) { for (const versionDataSub of Object.keys(source)) { const versionDataSubChanged = versionDataSub.replace(/\./g, "_"); diff --git a/functions/src/scripts/dataConvert.ts b/functions/src/scripts/dataConvert.ts index a2df1b1..e4e51d0 100644 --- a/functions/src/scripts/dataConvert.ts +++ b/functions/src/scripts/dataConvert.ts @@ -1,3 +1,5 @@ +//This file converts all data from JSON file into desired format for each tree + import * as validCheck from './validData'; export function getCVEs(data: { vulnerabilities: any; ASB: any; published: any; }, versionNumber: string): Record { @@ -9,7 +11,7 @@ export function getCVEs(data: { vulnerabilities: any; ASB: any; published: any; } if (!regex.test(vul.CVE)) { const editedID = validCheck.checkCVEValidity(vul.CVE, regex); //check if CVE is valid but malformed - if (editedID.length === 1) { //only one ID + if (editedID.length === 1) { //only one ID in ID slot vul.CVE = editedID[0]; subCVEData[vul.CVE] = buildSubCVEData(vul, versionNumber, data.published); @@ -38,14 +40,14 @@ function buildSubCVEData(vulnerability: any, versionNum: any, publishDate: any): } function buildSubCVEDataMultiple(vulnerability: any, versionNum: any, publishDate: any, ID: string): any { + //if there aare two ids in one slot const cveData: Record = {}; cveData['published_date'] = publishDate; cveData['BulletinVersion'] = Object(versionNum); for (const key of Object.keys(vulnerability)) { if (key === "CVE") { cveData[key] = Object(ID); - } - else { + } else { cveData[key] = vulnerability[key]; } } @@ -61,33 +63,33 @@ export function buildCVEHistoryTree(tree: any, versionHistory: string, cveTree: if (tree === null) { const returnMap = new Map(); //if no data present in history tree, send reconfigured cve tree - for (const ID in cveTree) { - const tempVersion = cveTree[ID]['BulletinVersion']; - delete cveTree[ID]['BulletinVersion']; - const tempLongVersionNumber = cveTree[ID]['ASB'] + ":" + tempVersion; - const tempArray = [tempLongVersionNumber, cveTree[ID]]; - returnMap.set(ID, tempArray); + for (const id in cveTree) { + const tempVersion = cveTree[id]['BulletinVersion']; + delete cveTree[id]['BulletinVersion']; + const tempLongVersionNumber = cveTree[id]['ASB'] + ":" + tempVersion; + const tempArray = [tempLongVersionNumber, cveTree[id]]; + returnMap.set(id, tempArray); } returnArray = [returnMap]; return returnArray; } else { const setMap = new Map(); const updateMap = new Map(); - for (const CVE in cveTree) { - if (!Object.values(cveTree).includes(CVE)) { + for (const cve in cveTree) { + if (!Object.values(cveTree).includes(cve)) { //if CVE not in CVE History tree add data - const tempVersion = cveTree[CVE]['BulletinVersion']; - delete cveTree[CVE]['BulletinVersion']; - const tempLongVersionNumber = cveTree[CVE]['ASB'] + ":" + tempVersion; - const tempArray = [tempLongVersionNumber, cveTree[CVE]]; - setMap.set(CVE, tempArray); + const tempVersion = cveTree[cve]['BulletinVersion']; + delete cveTree[cve]['BulletinVersion']; + const tempLongVersionNumber = cveTree[cve]['ASB'] + ":" + tempVersion; + const tempArray = [tempLongVersionNumber, cveTree[cve]]; + setMap.set(cve, tempArray); } } - for (const CVE in tree) { + for (const cve in tree) { //check if latest version in history tree - const currentTreeCVEData = tree[CVE]; + const currentTreeCVEData = tree[cve]; let hasKey = false; - if (jsonData[CVE] !== undefined) { + if (jsonData[cve] !== undefined) { for (const key of Object.keys(currentTreeCVEData)) { if (key === longVersionNumberHistory) { hasKey = true; @@ -97,13 +99,13 @@ export function buildCVEHistoryTree(tree: any, versionHistory: string, cveTree: //if doesn't have version add in the data const cveData: Record = {}; cveData['published_date'] = jsonData.published; - for (const key of Object.keys(jsonData[CVE])) { - cveData[key] = jsonData[CVE][key]; + for (const key of Object.keys(jsonData[cve])) { + cveData[key] = jsonData[cve][key]; } const constructedData = JSON.parse(JSON.stringify(cveData)); delete constructedData['BulletinVersion']; const tempArray = [longVersionNumberHistory, constructedData]; - updateMap.set(CVE, tempArray); + updateMap.set(cve, tempArray); } } } @@ -130,11 +132,12 @@ export function buildBulletinSPLTree(tree: any): Map> { const currentASB = cveData.ASB; let currentSPL = cveData.patch_level if (currentSPL === undefined || currentSPL === null) { + //missing patch level currentSPL = currentASB + "-01"; } if (currentASB && currentSPL) { const previousSet = asbSPlMap.get(currentASB); - if (previousSet) { + if (previousSet) { //already has a mapping asbSPlMap.set(currentASB, previousSet.add(currentSPL)); } else { const newSet = new Set(); @@ -163,12 +166,13 @@ export function buildSPLCVEIDTree(tree: any): Map { const cveData = tree[cve]; let currentSPL = cveData.patch_level; if (currentSPL === null || currentSPL === undefined) { + //missing patch level currentSPL = cveData.ASB + "-01"; } splPublishDateMap.set(currentSPL, cveData.published_date); if (currentSPL) { - const previousSet = splCVEIDMap.get(currentSPL); - if (previousSet) { + const previousSet = splCVEIDMap.get(currentSPL); + if (previousSet) { //already has a mapping splCVEIDMap.set(currentSPL, previousSet.add(cve)); } else { const newSet = new Set(); @@ -199,11 +203,12 @@ export function buildSPLCVEIDTree(tree: any): Map { export function buildAOSPVersionASBCVEIDTree(tree: any): Map { const asbCVEIDMap = new Map>(); const aospASBMap = new Map>(); + //will create two maps that are later combined for (const cve in tree) { const tempCVEData = tree[cve]; if (tempCVEData.ASB && cve) { const previousMap = asbCVEIDMap.get(tempCVEData.ASB); - if (previousMap) { + if (previousMap) { //already has a mapping asbCVEIDMap.set(tempCVEData.ASB, previousMap.add(cve)); } else { const newSet = new Set(); @@ -216,7 +221,7 @@ export function buildAOSPVersionASBCVEIDTree(tree: any): Map { const aospVersion = tempCVEData.aosp_versions[aospNumber]; if (aospVersion && cve && tempCVEData.ASB) { const previousMap = aospASBMap.get(aospVersion); - if (previousMap) { + if (previousMap) { //already has a mapping aospASBMap.set(aospVersion, previousMap.add(tempCVEData.ASB)); } else { const newSet = new Set(); @@ -234,18 +239,19 @@ export function buildAOSPVersionASBCVEIDTree(tree: any): Map { for (const currentEntry of asbCVEIDSet) { const set = asbCVEIDMap.get(currentEntry); let array = null; - if (set !== undefined) { + if (set) { const iterator = set[Symbol.iterator](); array = Array.from(iterator); for (let i = 0; i < array.length; i++) { if (!validCheck.isAndroidVersionSupported(tree, key, array[i])) { + //if android version is in aosp version list array.splice(i, 1); i--; } } JSON.parse(JSON.stringify(array)); } - const tempKey = key.replace(/\./g, "_"); + const tempKey = key.replace(/\./g, "_"); //keys cannot have periods in RTDB const tempArray = [currentEntry, array]; returnMap.set(tempKey,tempArray); } @@ -263,7 +269,7 @@ export function buildAOSPVersionCVEIDTree(tree: any): Map> { aospVersion = aospVersion.replace(/\./g, "_"); if (cve) { const previousSet = aospCVEIDMap.get(aospVersion); - if (previousSet) { + if (previousSet) { //already has mapping aospCVEIDMap.set(aospVersion, previousSet.add(cve)); } else { const newSet = new Set(); @@ -300,8 +306,7 @@ export function buildBulletinVersionTree(tree: any): Map> if (bulletinVersionCurrentValue && currentVersion >= bulletinVersionCurrentValue[0]) { const arrayToAdd: string[] = [currentVersion, cveData.published_date]; bulletinVersionMap.set(currentASB, arrayToAdd); - } - else if (bulletinVersionCurrentValue === null || bulletinVersionCurrentValue === undefined) { + } else if (bulletinVersionCurrentValue === null || bulletinVersionCurrentValue === undefined) { const arrayToAdd: string[] = [currentVersion, cveData.published_date]; bulletinVersionMap.set(currentASB, arrayToAdd); } diff --git a/functions/src/scripts/dbInteraction.ts b/functions/src/scripts/dbInteraction.ts index be7b86a..fe532cd 100644 --- a/functions/src/scripts/dbInteraction.ts +++ b/functions/src/scripts/dbInteraction.ts @@ -1,3 +1,5 @@ +//This file sends all converted trees to RTDB + import * as admin from 'firebase-admin'; import * as dataConversion from './dataConvert'; import * as cleanupFunction from './cleanupData'; @@ -42,8 +44,7 @@ function sendCVEHistoryToDB(treeToSend:any): any { for (const key of map.keys()) promises.push(ref.child(key).child(map.get(key)[0]).set(map.get(key)[1]).catch( error => { console.log("Error adding all current CVE Tree data into blank history tree:" + error) })); - } - else { + } else { const setMap = treeToSend[0]; const updateMap = treeToSend[1]; for (const key of setMap.keys()){ @@ -68,7 +69,6 @@ function writeToDatabaseCVETree(data: any, versionNum: string, longNum: any): Pr const promises = []; promises.push(dataConversion.buildCVETree(data, versionNum, result)); return Promise.all(promises); - }) return currentTreeCheck.then(async (versionCheck) => { @@ -79,8 +79,7 @@ function writeToDatabaseCVETree(data: any, versionNum: string, longNum: any): Pr } console.log("CVE Tree uploaded"); return pullFromDatabase(longNum, versionNum.toString(), data); - } - else { + } else { console.log("Version older than most recent one in db - can't load in data"); } }).catch(error => { console.log("Error checking bulletin version and writing cve tree to db" + error) }); diff --git a/functions/src/scripts/readInputScript.ts b/functions/src/scripts/readInputScript.ts index d0d1e6d..340d85d 100644 --- a/functions/src/scripts/readInputScript.ts +++ b/functions/src/scripts/readInputScript.ts @@ -1,4 +1,7 @@ +//This file reads in the JSON file if inputted from the command line + import * as yargs from 'yargs'; + const args = yargs.option('inputPath', { alias: 'i', demand: true, type: 'string' }).argv; export function getConvertedInputFile(): any { diff --git a/functions/src/scripts/readInputUpload.ts b/functions/src/scripts/readInputUpload.ts index 6931360..e28a8d4 100644 --- a/functions/src/scripts/readInputUpload.ts +++ b/functions/src/scripts/readInputUpload.ts @@ -1,3 +1,4 @@ +//This file reads in the JSON file if inputted from the UI export function getConvertedInputFile(filePath: string): any { const rawBulletin = readInputFile(filePath); //read bulletin json file diff --git a/functions/src/scripts/validData.ts b/functions/src/scripts/validData.ts index 9e64dc8..98c8556 100644 --- a/functions/src/scripts/validData.ts +++ b/functions/src/scripts/validData.ts @@ -1,3 +1,5 @@ +//This file validates and checks data from the bulletin JSON file + export function checkCVEValidity(ID: string, regExpression: any): any { //These are the types of malformations found thus far const finalID: any[] = []; diff --git a/functions/src/upload/index.ts b/functions/src/upload/index.ts index c58c5d9..8c2ad23 100644 --- a/functions/src/upload/index.ts +++ b/functions/src/upload/index.ts @@ -1,9 +1,10 @@ +//This file saves the JSON file to firebase storage and downloads it to temporary path + import * as functions from 'firebase-functions'; import * as admin from 'firebase-admin'; import * as converterScript from '../scripts/uploadConverter'; export const getUpload = functions.storage.object().onFinalize(async (object) => { - const path = require('path'); const os = require('os'); const fs = require('fs'); @@ -20,6 +21,6 @@ export const getUpload = functions.storage.object().onFinalize(async (object) => } console.log('File downloaded locally to', tempFilePath); await converterScript.getUploadConvert(tempFilePath); - fs.unlinkSync(tempFilePath); + fs.unlinkSync(tempFilePath); //remove temp file }); diff --git a/functions/test/dataConvertTest.ts b/functions/test/dataConvertTest.ts index 4e4b5b0..53db30f 100644 --- a/functions/test/dataConvertTest.ts +++ b/functions/test/dataConvertTest.ts @@ -1,3 +1,5 @@ +//This file tests the data conversion file + import 'mocha'; import * as chai from 'chai'; diff --git a/functions/test/validDataTest.ts b/functions/test/validDataTest.ts index fccec1f..757e057 100644 --- a/functions/test/validDataTest.ts +++ b/functions/test/validDataTest.ts @@ -1,3 +1,5 @@ +//This file tests the valid data file + import 'mocha'; import * as chai from 'chai';