Add incoming request response sent payloads validatio
authorJérôme Benoit <jerome.benoit@sap.com>
Sun, 8 Jan 2023 15:04:42 +0000 (16:04 +0100)
committerJérôme Benoit <jerome.benoit@sap.com>
Sun, 8 Jan 2023 15:04:42 +0000 (16:04 +0100)
Signed-off-by: Jérôme Benoit <jerome.benoit@sap.com>
src/charging-station/ocpp/1.6/OCPP16ResponseService.ts
src/charging-station/ocpp/2.0/OCPP20ResponseService.ts
src/charging-station/ocpp/OCPPRequestService.ts
src/charging-station/ocpp/OCPPServiceUtils.ts

index 061466e8df4b8e4ce5df5440e793836021f18f71..e29957be3fdacebd525abc872cf9f5a466c22cee 100644 (file)
@@ -22,11 +22,20 @@ import {
   type OCPP16StatusNotificationRequest,
 } from '../../../types/ocpp/1.6/Requests';
 import type {
+  ChangeAvailabilityResponse,
+  ChangeConfigurationResponse,
+  ClearChargingProfileResponse,
   DiagnosticsStatusNotificationResponse,
+  GetConfigurationResponse,
+  GetDiagnosticsResponse,
   OCPP16BootNotificationResponse,
   OCPP16DataTransferResponse,
   OCPP16HeartbeatResponse,
   OCPP16StatusNotificationResponse,
+  OCPP16TriggerMessageResponse,
+  OCPP16UpdateFirmwareResponse,
+  SetChargingProfileResponse,
+  UnlockConnectorResponse,
 } from '../../../types/ocpp/1.6/Responses';
 import {
   OCPP16AuthorizationStatus,
@@ -39,7 +48,11 @@ import {
 } from '../../../types/ocpp/1.6/Transaction';
 import { ErrorType } from '../../../types/ocpp/ErrorType';
 import { OCPPVersion } from '../../../types/ocpp/OCPPVersion';
-import { RegistrationStatusEnumType, type ResponseHandler } from '../../../types/ocpp/Responses';
+import {
+  type DefaultResponse,
+  RegistrationStatusEnumType,
+  type ResponseHandler,
+} from '../../../types/ocpp/Responses';
 import Constants from '../../../utils/Constants';
 import logger from '../../../utils/Logger';
 import Utils from '../../../utils/Utils';
@@ -185,7 +198,176 @@ export default class OCPP16ResponseService extends OCPPResponseService {
         ) as JSONSchemaType<OCPP16DataTransferResponse>,
       ],
     ]);
-    this.jsonIncomingRequestResponseSchemas = new Map();
+    this.jsonIncomingRequestResponseSchemas = new Map([
+      [
+        OCPP16IncomingRequestCommand.RESET,
+        JSON.parse(
+          fs.readFileSync(
+            path.resolve(
+              path.dirname(fileURLToPath(import.meta.url)),
+              '../../../assets/json-schemas/ocpp/1.6/ResetResponse.json'
+            ),
+            'utf8'
+          )
+        ) as JSONSchemaType<DefaultResponse>,
+      ],
+      [
+        OCPP16IncomingRequestCommand.CLEAR_CACHE,
+        JSON.parse(
+          fs.readFileSync(
+            path.resolve(
+              path.dirname(fileURLToPath(import.meta.url)),
+              '../../../assets/json-schemas/ocpp/1.6/ClearCacheResponse.json'
+            ),
+            'utf8'
+          )
+        ) as JSONSchemaType<DefaultResponse>,
+      ],
+      [
+        OCPP16IncomingRequestCommand.CHANGE_AVAILABILITY,
+        JSON.parse(
+          fs.readFileSync(
+            path.resolve(
+              path.dirname(fileURLToPath(import.meta.url)),
+              '../../../assets/json-schemas/ocpp/1.6/ChangeAvailabilityResponse.json'
+            ),
+            'utf8'
+          )
+        ) as JSONSchemaType<ChangeAvailabilityResponse>,
+      ],
+      [
+        OCPP16IncomingRequestCommand.UNLOCK_CONNECTOR,
+        JSON.parse(
+          fs.readFileSync(
+            path.resolve(
+              path.dirname(fileURLToPath(import.meta.url)),
+              '../../../assets/json-schemas/ocpp/1.6/UnlockConnectorResponse.json'
+            ),
+            'utf8'
+          )
+        ) as JSONSchemaType<UnlockConnectorResponse>,
+      ],
+      [
+        OCPP16IncomingRequestCommand.GET_CONFIGURATION,
+        JSON.parse(
+          fs.readFileSync(
+            path.resolve(
+              path.dirname(fileURLToPath(import.meta.url)),
+              '../../../assets/json-schemas/ocpp/1.6/GetConfigurationResponse.json'
+            ),
+            'utf8'
+          )
+        ) as JSONSchemaType<GetConfigurationResponse>,
+      ],
+      [
+        OCPP16IncomingRequestCommand.CHANGE_CONFIGURATION,
+        JSON.parse(
+          fs.readFileSync(
+            path.resolve(
+              path.dirname(fileURLToPath(import.meta.url)),
+              '../../../assets/json-schemas/ocpp/1.6/ChangeConfigurationResponse.json'
+            ),
+            'utf8'
+          )
+        ) as JSONSchemaType<ChangeConfigurationResponse>,
+      ],
+      [
+        OCPP16IncomingRequestCommand.SET_CHARGING_PROFILE,
+        JSON.parse(
+          fs.readFileSync(
+            path.resolve(
+              path.dirname(fileURLToPath(import.meta.url)),
+              '../../../assets/json-schemas/ocpp/1.6/SetChargingProfileResponse.json'
+            ),
+            'utf8'
+          )
+        ) as JSONSchemaType<SetChargingProfileResponse>,
+      ],
+      [
+        OCPP16IncomingRequestCommand.CLEAR_CHARGING_PROFILE,
+        JSON.parse(
+          fs.readFileSync(
+            path.resolve(
+              path.dirname(fileURLToPath(import.meta.url)),
+              '../../../assets/json-schemas/ocpp/1.6/ClearChargingProfileResponse.json'
+            ),
+            'utf8'
+          )
+        ) as JSONSchemaType<ClearChargingProfileResponse>,
+      ],
+      [
+        OCPP16IncomingRequestCommand.REMOTE_START_TRANSACTION,
+        JSON.parse(
+          fs.readFileSync(
+            path.resolve(
+              path.dirname(fileURLToPath(import.meta.url)),
+              '../../../assets/json-schemas/ocpp/1.6/RemoteStartTransactionResponse.json'
+            ),
+            'utf8'
+          )
+        ) as JSONSchemaType<DefaultResponse>,
+      ],
+      [
+        OCPP16IncomingRequestCommand.REMOTE_STOP_TRANSACTION,
+        JSON.parse(
+          fs.readFileSync(
+            path.resolve(
+              path.dirname(fileURLToPath(import.meta.url)),
+              '../../../assets/json-schemas/ocpp/1.6/RemoteStopTransactionResponse.json'
+            ),
+            'utf8'
+          )
+        ) as JSONSchemaType<DefaultResponse>,
+      ],
+      [
+        OCPP16IncomingRequestCommand.GET_DIAGNOSTICS,
+        JSON.parse(
+          fs.readFileSync(
+            path.resolve(
+              path.dirname(fileURLToPath(import.meta.url)),
+              '../../../assets/json-schemas/ocpp/1.6/GetDiagnosticsResponse.json'
+            ),
+            'utf8'
+          )
+        ) as JSONSchemaType<GetDiagnosticsResponse>,
+      ],
+      [
+        OCPP16IncomingRequestCommand.TRIGGER_MESSAGE,
+        JSON.parse(
+          fs.readFileSync(
+            path.resolve(
+              path.dirname(fileURLToPath(import.meta.url)),
+              '../../../assets/json-schemas/ocpp/1.6/TriggerMessageResponse.json'
+            ),
+            'utf8'
+          )
+        ) as JSONSchemaType<OCPP16TriggerMessageResponse>,
+      ],
+      [
+        OCPP16IncomingRequestCommand.DATA_TRANSFER,
+        JSON.parse(
+          fs.readFileSync(
+            path.resolve(
+              path.dirname(fileURLToPath(import.meta.url)),
+              '../../../assets/json-schemas/ocpp/1.6/DataTransferResponse.json'
+            ),
+            'utf8'
+          )
+        ) as JSONSchemaType<OCPP16DataTransferResponse>,
+      ],
+      [
+        OCPP16IncomingRequestCommand.UPDATE_FIRMWARE,
+        JSON.parse(
+          fs.readFileSync(
+            path.resolve(
+              path.dirname(fileURLToPath(import.meta.url)),
+              '../../../assets/json-schemas/ocpp/1.6/UpdateFirmwareResponse.json'
+            ),
+            'utf8'
+          )
+        ) as JSONSchemaType<OCPP16UpdateFirmwareResponse>,
+      ],
+    ]);
     this.validatePayload.bind(this);
   }
 
index acef3c9778774b4baea79609f6ca7506c0be4a8e..ef83ad4376c1e1d4fdecb99d04cb208b8b940242 100644 (file)
@@ -12,7 +12,10 @@ import {
   OCPP20IncomingRequestCommand,
   OCPP20RequestCommand,
 } from '../../../types/ocpp/2.0/Requests';
-import type { OCPP20BootNotificationResponse } from '../../../types/ocpp/2.0/Responses';
+import type {
+  OCPP20BootNotificationResponse,
+  OCPP20ClearCacheResponse,
+} from '../../../types/ocpp/2.0/Responses';
 import { ErrorType } from '../../../types/ocpp/ErrorType';
 import { OCPPVersion } from '../../../types/ocpp/OCPPVersion';
 import { RegistrationStatusEnumType, ResponseHandler } from '../../../types/ocpp/Responses';
@@ -54,7 +57,20 @@ export default class OCPP20ResponseService extends OCPPResponseService {
         ) as JSONSchemaType<OCPP20BootNotificationResponse>,
       ],
     ]);
-    this.jsonIncomingRequestResponseSchemas = new Map();
+    this.jsonIncomingRequestResponseSchemas = new Map([
+      [
+        OCPP20IncomingRequestCommand.CLEAR_CACHE,
+        JSON.parse(
+          fs.readFileSync(
+            path.resolve(
+              path.dirname(fileURLToPath(import.meta.url)),
+              '../../../assets/json-schemas/ocpp/2.0/ClearCacheResponse.json'
+            ),
+            'utf8'
+          )
+        ) as JSONSchemaType<OCPP20ClearCacheResponse>,
+      ],
+    ]);
     this.validatePayload.bind(this);
   }
 
index 6c0e7b0db4c571064ffb4ceacf474841df0df526..d14fb5703a09deea352195560ae0e98c55dc56af 100644 (file)
@@ -50,6 +50,7 @@ export default abstract class OCPPRequestService {
     this.internalSendMessage.bind(this);
     this.buildMessageToSend.bind(this);
     this.validateRequestPayload.bind(this);
+    this.validateIncomingRequestResponsePayload.bind(this);
   }
 
   public static getInstance<T extends OCPPRequestService>(
@@ -128,7 +129,7 @@ export default abstract class OCPPRequestService {
     }
   }
 
-  protected validateRequestPayload<T extends JsonObject>(
+  private validateRequestPayload<T extends JsonObject>(
     chargingStation: ChargingStation,
     commandName: RequestCommand | IncomingRequestCommand,
     payload: T
@@ -161,7 +162,7 @@ export default abstract class OCPPRequestService {
     );
   }
 
-  protected validateResponsePayload<T extends JsonObject>(
+  private validateIncomingRequestResponsePayload<T extends JsonObject>(
     chargingStation: ChargingStation,
     commandName: RequestCommand | IncomingRequestCommand,
     payload: T
@@ -175,7 +176,7 @@ export default abstract class OCPPRequestService {
       ) === false
     ) {
       logger.warn(
-        `${chargingStation.logPrefix()} ${moduleName}.validateResponsePayload: No JSON schema found for command '${commandName}' PDU validation`
+        `${chargingStation.logPrefix()} ${moduleName}.validateIncomingRequestResponsePayload: No JSON schema found for command '${commandName}' PDU validation`
       );
       return true;
     }
@@ -190,7 +191,7 @@ export default abstract class OCPPRequestService {
       return true;
     }
     logger.error(
-      `${chargingStation.logPrefix()} ${moduleName}.validateResponsePayload: Command '${commandName}' reponse PDU is invalid: %j`,
+      `${chargingStation.logPrefix()} ${moduleName}.validateIncomingRequestResponsePayload: Command '${commandName}' reponse PDU is invalid: %j`,
       validate.errors
     );
     // OCPPError usage here is debatable: it's an error in the OCPP stack but not targeted to sendError().
@@ -389,7 +390,11 @@ export default abstract class OCPPRequestService {
       // Response
       case MessageType.CALL_RESULT_MESSAGE:
         // Build response
-        this.validateResponsePayload(chargingStation, commandName, messagePayload as JsonObject);
+        this.validateIncomingRequestResponsePayload(
+          chargingStation,
+          commandName,
+          messagePayload as JsonObject
+        );
         messageToSend = JSON.stringify([messageType, messageId, messagePayload] as Response);
         break;
       // Error Message
index 574476c64d5762e148e3536234c2d9955d4f9386..3c41525140774d82d9f459208ea15ee7941cf988 100644 (file)
@@ -106,11 +106,11 @@ export class OCPPServiceUtils {
   }
 
   public static convertDateToISOString<T extends JsonType>(obj: T): void {
-    for (const k in obj) {
-      if (obj[k] instanceof Date) {
-        (obj as JsonObject)[k] = (obj[k] as Date).toISOString();
-      } else if (obj[k] !== null && typeof obj[k] === 'object') {
-        this.convertDateToISOString<T>(obj[k] as T);
+    for (const key in obj) {
+      if (obj[key] instanceof Date) {
+        (obj as JsonObject)[key] = (obj[key] as Date).toISOString();
+      } else if (obj[key] !== null && typeof obj[key] === 'object') {
+        this.convertDateToISOString<T>(obj[key] as T);
       }
     }
   }