From 53e5fd67dea2dd83ec9c34d963dd6e502ec46f5c Mon Sep 17 00:00:00 2001 From: =?utf8?q?J=C3=A9r=C3=B4me=20Benoit?= Date: Wed, 24 Aug 2022 22:10:01 +0200 Subject: [PATCH] Improve payload type checking in OCPP, UI and Broadcast Channel protocols MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Signed-off-by: Jérôme Benoit --- src/charging-station/Bootstrap.ts | 5 +++-- src/charging-station/ChargingStation.ts | 14 +++++++------- .../ChargingStationWorkerBroadcastChannel.ts | 3 +++ .../UIServiceWorkerBroadcastChannel.ts | 4 ++++ .../ui-server/ui-services/AbstractUIService.ts | 5 ++--- src/types/ChargingStationWorker.ts | 3 +++ src/ui/web/src/composable/UIClient.ts | 4 ++-- src/utils/Configuration.ts | 2 +- 8 files changed, 25 insertions(+), 15 deletions(-) diff --git a/src/charging-station/Bootstrap.ts b/src/charging-station/Bootstrap.ts index 516730b9..2bc650cc 100644 --- a/src/charging-station/Bootstrap.ts +++ b/src/charging-station/Bootstrap.ts @@ -14,6 +14,7 @@ import { ChargingStationData, ChargingStationWorkerData, ChargingStationWorkerMessage, + ChargingStationWorkerMessageData, ChargingStationWorkerMessageEvents, } from '../types/ChargingStationWorker'; import { StationTemplateUrl } from '../types/ConfigurationData'; @@ -173,14 +174,14 @@ export default class Bootstrap { workerChoiceStrategy: Configuration.getWorker().poolStrategy, }, messageHandler: this.messageHandler.bind(this) as ( - msg: ChargingStationWorkerMessage + msg: ChargingStationWorkerMessage ) => void, } )); } private messageHandler( - msg: ChargingStationWorkerMessage + msg: ChargingStationWorkerMessage ): void { // logger.debug( // `${this.logPrefix()} ${moduleName}.messageHandler: Worker channel message received: ${JSON.stringify( diff --git a/src/charging-station/ChargingStation.ts b/src/charging-station/ChargingStation.ts index 25d9733b..5631a984 100644 --- a/src/charging-station/ChargingStation.ts +++ b/src/charging-station/ChargingStation.ts @@ -626,7 +626,7 @@ export default class ChargingStation { ); this.getConnectorStatus(connectorId).chargingProfiles = []; } - if (!Array.isArray(this.getConnectorStatus(connectorId).chargingProfiles)) { + if (Array.isArray(this.getConnectorStatus(connectorId).chargingProfiles) === false) { logger.error( `${this.logPrefix()} Trying to set a charging profile on connectorId ${connectorId} with an improper attribute type for the charging profiles array, applying proper type initialization` ); @@ -1419,7 +1419,7 @@ export default class ChargingStation { let errMsg: string; try { const request = JSON.parse(data.toString()) as IncomingRequest | Response | ErrorResponse; - if (Utils.isIterable(request)) { + if (Array.isArray(request) === true) { [messageType, messageId] = request; // Check the type of message switch (messageType) { @@ -1456,12 +1456,12 @@ export default class ChargingStation { } // Respond cachedRequest = this.requests.get(messageId); - if (Utils.isIterable(cachedRequest)) { + if (Array.isArray(cachedRequest) === true) { [responseCallback, , requestCommandName, requestPayload] = cachedRequest; } else { throw new OCPPError( ErrorType.PROTOCOL_ERROR, - `Cached request for message id ${messageId} response is not iterable`, + `Cached request for message id ${messageId} response is not an array`, null, cachedRequest as unknown as JsonType ); @@ -1486,12 +1486,12 @@ export default class ChargingStation { ); } cachedRequest = this.requests.get(messageId); - if (Utils.isIterable(cachedRequest)) { + if (Array.isArray(cachedRequest) === true) { [, errorCallback, requestCommandName] = cachedRequest; } else { throw new OCPPError( ErrorType.PROTOCOL_ERROR, - `Cached request for message id ${messageId} error response is not iterable`, + `Cached request for message id ${messageId} error response is not an array`, null, cachedRequest as unknown as JsonType ); @@ -1512,7 +1512,7 @@ export default class ChargingStation { } parentPort.postMessage(MessageChannelUtils.buildUpdatedMessage(this)); } else { - throw new OCPPError(ErrorType.PROTOCOL_ERROR, 'Incoming message is not iterable', null, { + throw new OCPPError(ErrorType.PROTOCOL_ERROR, 'Incoming message is not an array', null, { payload: request, }); } diff --git a/src/charging-station/ChargingStationWorkerBroadcastChannel.ts b/src/charging-station/ChargingStationWorkerBroadcastChannel.ts index 18cbadef..4e43e5ad 100644 --- a/src/charging-station/ChargingStationWorkerBroadcastChannel.ts +++ b/src/charging-station/ChargingStationWorkerBroadcastChannel.ts @@ -38,6 +38,9 @@ export default class ChargingStationWorkerBroadcastChannel extends WorkerBroadca if (this.isResponse(messageEvent.data)) { return; } + if (Array.isArray(messageEvent.data) === false) { + throw new BaseError('Worker broadcast channel protocol request is not an array'); + } const [uuid, command, requestPayload] = messageEvent.data as BroadcastChannelRequest; diff --git a/src/charging-station/UIServiceWorkerBroadcastChannel.ts b/src/charging-station/UIServiceWorkerBroadcastChannel.ts index d50d514a..a94f2b31 100644 --- a/src/charging-station/UIServiceWorkerBroadcastChannel.ts +++ b/src/charging-station/UIServiceWorkerBroadcastChannel.ts @@ -1,3 +1,4 @@ +import BaseError from '../exception/BaseError'; import { BroadcastChannelResponse, MessageEvent } from '../types/WorkerBroadcastChannel'; import logger from '../utils/Logger'; import type AbstractUIService from './ui-server/ui-services/AbstractUIService'; @@ -19,6 +20,9 @@ export default class UIServiceWorkerBroadcastChannel extends WorkerBroadcastChan if (this.isRequest(messageEvent.data)) { return; } + if (Array.isArray(messageEvent.data) === false) { + throw new BaseError('Worker broadcast channel protocol response is not an array'); + } const [uuid, responsePayload] = messageEvent.data as BroadcastChannelResponse; this.uiService.sendResponse(uuid, responsePayload); diff --git a/src/charging-station/ui-server/ui-services/AbstractUIService.ts b/src/charging-station/ui-server/ui-services/AbstractUIService.ts index 224f78a2..ff44954a 100644 --- a/src/charging-station/ui-server/ui-services/AbstractUIService.ts +++ b/src/charging-station/ui-server/ui-services/AbstractUIService.ts @@ -13,7 +13,6 @@ import { ResponseStatus, } from '../../../types/UIProtocol'; import logger from '../../../utils/Logger'; -import Utils from '../../../utils/Utils'; import Bootstrap from '../../Bootstrap'; import UIServiceWorkerBroadcastChannel from '../../UIServiceWorkerBroadcastChannel'; import type { AbstractUIServer } from '../AbstractUIServer'; @@ -119,8 +118,8 @@ export default abstract class AbstractUIService { const data = JSON.parse(rawData.toString()) as JsonType[]; - if (Utils.isIterable(data) === false) { - throw new BaseError('UI protocol request is not iterable'); + if (Array.isArray(data) === false) { + throw new BaseError('UI protocol request is not an array'); } if (data.length !== 3) { diff --git a/src/types/ChargingStationWorker.ts b/src/types/ChargingStationWorker.ts index 1a48e96d..0fba406b 100644 --- a/src/types/ChargingStationWorker.ts +++ b/src/types/ChargingStationWorker.ts @@ -1,6 +1,7 @@ import ChargingStationInfo from './ChargingStationInfo'; import { ConnectorStatus } from './ConnectorStatus'; import { JsonObject } from './JsonType'; +import Statistics from './Statistics'; import { WorkerData, WorkerMessage, WorkerMessageEvents } from './Worker'; export interface ChargingStationWorkerOptions extends JsonObject { @@ -34,6 +35,8 @@ export const ChargingStationWorkerMessageEvents = { ...ChargingStationMessageEvents, }; +export type ChargingStationWorkerMessageData = ChargingStationData | Statistics; + export interface ChargingStationWorkerMessage extends Omit, 'id'> { id: ChargingStationWorkerMessageEvents; diff --git a/src/ui/web/src/composable/UIClient.ts b/src/ui/web/src/composable/UIClient.ts index eb8e013e..6803ef03 100644 --- a/src/ui/web/src/composable/UIClient.ts +++ b/src/ui/web/src/composable/UIClient.ts @@ -112,8 +112,8 @@ export default class UIClient { private responseHandler(messageEvent: MessageEvent): void { const data = JSON.parse(messageEvent.data) as ProtocolResponse; - if (Utils.isIterable(data) === false) { - throw new Error('Response not iterable: ' + JSON.stringify(data, null, 2)); + if (Array.isArray(data) === false) { + throw new Error('Response not an array: ' + JSON.stringify(data, null, 2)); } const [uuid, response] = data; diff --git a/src/utils/Configuration.ts b/src/utils/Configuration.ts index c185133a..5de86714 100644 --- a/src/utils/Configuration.ts +++ b/src/utils/Configuration.ts @@ -389,7 +389,7 @@ export default class Configuration { } private static isObject(item): boolean { - return item && typeof item === 'object' && !Array.isArray(item); + return item && typeof item === 'object' && Array.isArray(item) === false; } private static deepMerge(target: object, ...sources: object[]): object { -- 2.34.1