Skip to content

Commit c646956

Browse files
authored
Merge pull request #1308 from CVEProject/dr_utc
Standardize all timestamps values to UTC
2 parents 9d92da9 + 6901b17 commit c646956

File tree

3 files changed

+72
-9
lines changed

3 files changed

+72
-9
lines changed

src/constants/index.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,9 @@ function getConstants () {
100100
CVE_ID_PATTERN: cveSchemaV5.definitions.cveId.pattern,
101101
// Ajv's pattern validation uses the "u" (unicode) flag:
102102
// https://ajv.js.org/json-schema.html#pattern
103-
CVE_ID_REGEX: new RegExp(cveSchemaV5.definitions.cveId.pattern, 'u')
103+
CVE_ID_REGEX: new RegExp(cveSchemaV5.definitions.cveId.pattern, 'u'),
104+
DATE_FIELDS: ['cveMetadata.datePublished', 'cveMetadata.dateUpdated', 'cveMetadata.dateReserved', 'providerMetadata.dateUpdated', 'datePublic', 'dateAssigned'
105+
]
104106
}
105107

106108
return defaults

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

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ const errors = require('./error')
44
const getConstants = require('../../constants').getConstants
55
const error = new errors.CveControllerError()
66
const booleanIsTrue = require('../../utils/utils').booleanIsTrue
7+
const convertDatesToISO = require('../../utils/utils').convertDatesToISO
78
const isEnrichedContainer = require('../../utils/utils').isEnrichedContainer
89
const url = process.env.NODE_ENV === 'staging' ? 'https://test.cve.org/' : 'https://cve.org/'
910

@@ -332,7 +333,7 @@ async function submitCve (req, res, next) {
332333
const CONSTANTS = getConstants()
333334

334335
try {
335-
const newCve = new Cve({ cve: req.ctx.body })
336+
const newCve = new Cve({ cve: convertDatesToISO(req.ctx.body, CONSTANTS.DATE_FIELDS) })
336337
const id = req.ctx.params.id
337338
const cveId = newCve.cve.cveMetadata.cveId
338339
const state = newCve.cve.cveMetadata.state
@@ -392,7 +393,8 @@ async function updateCve (req, res, next) {
392393
const CONSTANTS = getConstants()
393394

394395
try {
395-
const newCve = new Cve({ cve: req.ctx.body })
396+
// All CVE fields are stored in UTC format, we need to check and convert dates to ISO before storing in the database.
397+
const newCve = new Cve({ cve: convertDatesToISO(req.ctx.body, CONSTANTS.DATE_FIELDS) })
396398
const cveId = req.ctx.params.id
397399
const cveRepo = req.ctx.repositories.getCveRepository()
398400
const cveIdRepo = req.ctx.repositories.getCveIdRepository()
@@ -486,7 +488,7 @@ async function submitCna (req, res, next) {
486488
return res.status(403).json(error.cveRecordExists())
487489
}
488490

489-
const cnaContainer = req.ctx.body.cnaContainer
491+
const cnaContainer = convertDatesToISO(req.ctx.body.cnaContainer, CONSTANTS.DATE_FIELDS)
490492
if (erlCheck && !isEnrichedContainer(cnaContainer)) {
491493
// Process the ERL check here
492494
return res.status(403).json(error.erlCheckFailed())
@@ -582,7 +584,7 @@ async function updateCna (req, res, next) {
582584
return res.status(403).json(error.cveRecordDne())
583585
}
584586

585-
const cnaContainer = req.ctx.body.cnaContainer
587+
const cnaContainer = convertDatesToISO(req.ctx.body.cnaContainer, CONSTANTS.DATE_FIELDS)
586588
if (erlCheck && !isEnrichedContainer(cnaContainer)) {
587589
// Process the ERL check here
588590
return res.status(403).json(error.erlCheckFailed())
@@ -684,7 +686,7 @@ async function rejectCVE (req, res, next) {
684686

685687
const providerMetadata = createProviderMetadata(providerOrgObj.UUID, req.ctx.org, (new Date()).toISOString())
686688
const rejectedCve = Cve.newRejectedCve(cveIdObj, req.ctx.body, owningCnaShortName, providerMetadata)
687-
const newCveObj = new Cve({ cve: rejectedCve })
689+
const newCveObj = new Cve({ cve: convertDatesToISO(rejectedCve, CONSTANTS.DATE_FIELDS) })
688690

689691
result = Cve.validateCveRecord(newCveObj.cve)
690692
if (!result.isValid) {
@@ -757,7 +759,7 @@ async function rejectExistingCve (req, res, next) {
757759

758760
// update CVE record to rejected
759761
const updatedRecord = Cve.updateCveToRejected(id, providerMetadata, result.cve, req.ctx.body)
760-
const updatedCve = new Cve({ cve: updatedRecord })
762+
const updatedCve = new Cve({ cve: convertDatesToISO(updatedRecord, CONSTANTS.DATE_FIELDS) })
761763

762764
result = Cve.validateCveRecord(updatedCve.cve)
763765
if (!result.isValid) {
@@ -867,7 +869,7 @@ async function insertAdp (req, res, next) {
867869
cveRecord.containers.adp.push(adpContainer)
868870
}
869871

870-
const cveModel = new Cve({ cve: cveRecord })
872+
const cveModel = new Cve({ cve: convertDatesToISO(cveRecord, CONSTANTS.DATE_FIELDS) })
871873
result = Cve.validateCveRecord(cveModel.cve)
872874
if (!result.isValid) {
873875
logger.error(JSON.stringify({ uuid: req.ctx.uuid, message: 'CVE JSON schema validation FAILED.' }))

src/utils/utils.js

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
const Org = require('../model/org')
22
const User = require('../model/user')
33
const getConstants = require('../constants').getConstants
4+
const _ = require('lodash')
45
const { DateTime } = require('luxon')
56

67
async function getOrgUUID (shortName) {
@@ -154,6 +155,62 @@ function toDate (val) {
154155
return result
155156
}
156157

158+
// Covert Dates to ISO format
159+
function convertDatesToISO (obj, dateKeys) {
160+
// Helper function to check if a value is a valid date
161+
function isValidDate (value) {
162+
return value instanceof Date && !isNaN(value)
163+
}
164+
165+
// Helper function to check if a string is a valid date
166+
function isStringDate (value) {
167+
const date = new Date(value)
168+
return !isNaN(date.getTime())
169+
}
170+
171+
function updateDateValue (objectToUpdate, key, value) {
172+
if (isValidDate(value)) {
173+
_.set(objectToUpdate, key, value.toISOString())
174+
} else if (typeof value === 'string' && isStringDate(value)) {
175+
_.set(objectToUpdate, key, new Date(value).toISOString())
176+
}
177+
}
178+
179+
// For the top layer object
180+
for (const key of dateKeys) {
181+
if (_.has(obj, key)) {
182+
const value = _.get(obj, key)
183+
updateDateValue(obj, key, value)
184+
}
185+
}
186+
187+
// For the ADP(s)
188+
if (_.has(obj, 'containers.adp')) {
189+
// Use lodash for each to loop over array and check for date keys
190+
_.each(obj.containers.adp, (adp) => {
191+
for (const key of dateKeys) {
192+
if (_.has(adp, key)) {
193+
const value = _.get(adp, key)
194+
updateDateValue(adp, key, value)
195+
}
196+
}
197+
})
198+
}
199+
// For the CNAs
200+
201+
if (_.has(obj, 'containers.cna')) {
202+
// Use lodash to check the containers.cna object for date keys
203+
for (const key of dateKeys) {
204+
if (_.has(obj.containers.cna, key)) {
205+
const value = _.get(obj.containers.cna, key)
206+
updateDateValue(obj.containers.cna, key, value)
207+
}
208+
}
209+
}
210+
211+
return obj
212+
}
213+
157214
function isEnrichedContainer (container) {
158215
const hasCvss = container?.metrics?.some(item => 'cvssV4_0' in item || 'cvssV3_1' in item || 'cvssV3_0' in item || 'cvssV2_0' in item)
159216
const hasCwe = container?.problemTypes?.some(pItem => pItem?.descriptions?.some(dItem => 'cweId' in dItem))
@@ -174,5 +231,7 @@ module.exports = {
174231
getUserUUID,
175232
reqCtxMapping,
176233
booleanIsTrue,
177-
toDate
234+
toDate,
235+
convertDatesToISO
236+
178237
}

0 commit comments

Comments
 (0)