From ecac380caad1e22e6bbd1ae048d2999ebee66249 Mon Sep 17 00:00:00 2001 From: =?utf8?q?J=C3=A9r=C3=B4me=20Benoit?= Date: Tue, 17 Mar 2026 13:21:30 +0100 Subject: [PATCH] fix(ocpp2): use convertToDate() for all incoming date fields in handlers Replace raw new Date(string) and direct string comparisons with convertToDate() for date fields in incoming OCPP 2.0 payloads: - validateChargingProfile: validFrom/validTo comparisons - validateChargingSchedule: startSchedule comparisons - simulateFirmwareUpdateLifecycle: retrieveDateTime/installDateTime - handleResponseHeartbeat: currentTime display - OCPP20CertificateManager: cert.validFrom/validTo validation --- .../ocpp/2.0/OCPP20CertificateManager.ts | 8 ++-- .../ocpp/2.0/OCPP20IncomingRequestService.ts | 37 +++++++++++-------- .../ocpp/2.0/OCPP20ResponseService.ts | 4 +- 3 files changed, 28 insertions(+), 21 deletions(-) diff --git a/src/charging-station/ocpp/2.0/OCPP20CertificateManager.ts b/src/charging-station/ocpp/2.0/OCPP20CertificateManager.ts index ea0a3a1f..e255cb2e 100644 --- a/src/charging-station/ocpp/2.0/OCPP20CertificateManager.ts +++ b/src/charging-station/ocpp/2.0/OCPP20CertificateManager.ts @@ -15,7 +15,7 @@ import { HashAlgorithmEnumType, InstallCertificateUseEnumType, } from '../../../types/ocpp/2.0/Common.js' -import { getErrorMessage } from '../../../utils/index.js' +import { convertToDate, getErrorMessage } from '../../../utils/index.js' /** * Interface for ChargingStation with certificate manager @@ -471,10 +471,12 @@ export class OCPP20CertificateManager { } const cert = new X509Certificate(firstCertMatch[0]) const now = new Date() - if (now < new Date(cert.validFrom)) { + const validFromDate = convertToDate(cert.validFrom) + const validToDate = convertToDate(cert.validTo) + if (validFromDate != null && now < validFromDate) { return { reason: 'Certificate is not yet valid', valid: false } } - if (now > new Date(cert.validTo)) { + if (validToDate != null && now > validToDate) { return { reason: 'Certificate has expired', valid: false } } if (!cert.issuer.trim()) { diff --git a/src/charging-station/ocpp/2.0/OCPP20IncomingRequestService.ts b/src/charging-station/ocpp/2.0/OCPP20IncomingRequestService.ts index 67492407..a06a56d0 100644 --- a/src/charging-station/ocpp/2.0/OCPP20IncomingRequestService.ts +++ b/src/charging-station/ocpp/2.0/OCPP20IncomingRequestService.ts @@ -127,7 +127,14 @@ import { OCPP20ChargingRateUnitEnumType, OCPP20ReasonEnumType, } from '../../../types/ocpp/2.0/Transaction.js' -import { Constants, generateUUID, logger, sleep, validateUUID } from '../../../utils/index.js' +import { + Constants, + convertToDate, + generateUUID, + logger, + sleep, + validateUUID, +} from '../../../utils/index.js' import { getConfigurationKey } from '../../ConfigurationKeyUtils.js' import { getIdTagsFile, @@ -3404,7 +3411,7 @@ export class OCPP20IncomingRequestService extends OCPPIncomingRequestService { // C12: If retrieveDateTime is in the future, send DownloadScheduled and wait const now = Date.now() - const retrieveTime = new Date(retrieveDateTime).getTime() + const retrieveTime = convertToDate(retrieveDateTime)?.getTime() ?? now if (retrieveTime > now) { await this.sendFirmwareStatusNotification( chargingStation, @@ -3456,8 +3463,8 @@ export class OCPP20IncomingRequestService extends OCPPIncomingRequestService { // C12: If installDateTime is in the future, send InstallScheduled and wait if (installDateTime != null) { - const installTime = new Date(installDateTime).getTime() const currentTime = Date.now() + const installTime = convertToDate(installDateTime)?.getTime() ?? currentTime if (installTime > currentTime) { await this.sendFirmwareStatusNotification( chargingStation, @@ -3760,8 +3767,10 @@ export class OCPP20IncomingRequestService extends OCPPIncomingRequestService { } const now = new Date() - if (chargingProfile.validFrom && chargingProfile.validTo) { - if (chargingProfile.validFrom >= chargingProfile.validTo) { + const validFromDate = convertToDate(chargingProfile.validFrom) + const validToDate = convertToDate(chargingProfile.validTo) + if (validFromDate && validToDate) { + if (validFromDate >= validToDate) { logger.warn( `${chargingStation.logPrefix()} ${moduleName}.validateChargingProfile: validFrom must be before validTo` ) @@ -3769,7 +3778,7 @@ export class OCPP20IncomingRequestService extends OCPPIncomingRequestService { } } - if (chargingProfile.validTo && chargingProfile.validTo <= now) { + if (validToDate && validToDate <= now) { logger.warn( `${chargingStation.logPrefix()} ${moduleName}.validateChargingProfile: Charging profile already expired` ) @@ -3942,22 +3951,18 @@ export class OCPP20IncomingRequestService extends OCPPIncomingRequestService { return false } - if ( - schedule.startSchedule && - chargingProfile.validFrom && - schedule.startSchedule < chargingProfile.validFrom - ) { + const startScheduleDate = convertToDate(schedule.startSchedule) + const validFromDate = convertToDate(chargingProfile.validFrom) + const validToDate = convertToDate(chargingProfile.validTo) + + if (startScheduleDate != null && validFromDate != null && startScheduleDate < validFromDate) { logger.warn( `${chargingStation.logPrefix()} ${moduleName}.validateChargingSchedule: Schedule start time cannot be before profile validFrom` ) return false } - if ( - schedule.startSchedule && - chargingProfile.validTo && - schedule.startSchedule >= chargingProfile.validTo - ) { + if (startScheduleDate != null && validToDate != null && startScheduleDate >= validToDate) { logger.warn( `${chargingStation.logPrefix()} ${moduleName}.validateChargingSchedule: Schedule start time must be before profile validTo` ) diff --git a/src/charging-station/ocpp/2.0/OCPP20ResponseService.ts b/src/charging-station/ocpp/2.0/OCPP20ResponseService.ts index 3ab8940a..118d79d3 100644 --- a/src/charging-station/ocpp/2.0/OCPP20ResponseService.ts +++ b/src/charging-station/ocpp/2.0/OCPP20ResponseService.ts @@ -25,7 +25,7 @@ import { type ResponseHandler, } from '../../../types/index.js' import { OCPP20AuthorizationStatusEnumType } from '../../../types/ocpp/2.0/Transaction.js' -import { logger } from '../../../utils/index.js' +import { convertToDate, logger } from '../../../utils/index.js' import { OCPPResponseService } from '../OCPPResponseService.js' import { OCPP20ServiceUtils } from './OCPP20ServiceUtils.js' @@ -214,7 +214,7 @@ export class OCPP20ResponseService extends OCPPResponseService { payload: OCPP20HeartbeatResponse ): void { logger.debug( - `${chargingStation.logPrefix()} ${moduleName}.handleResponseHeartbeat: Heartbeat response received at ${payload.currentTime.toISOString()}` + `${chargingStation.logPrefix()} ${moduleName}.handleResponseHeartbeat: Heartbeat response received at ${convertToDate(payload.currentTime)?.toISOString() ?? 'unknown'}` ) } -- 2.43.0