const moduleName = 'OCPP16IncomingRequestService';
export default class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
+ protected jsonSchemas: Map<OCPP16IncomingRequestCommand, JSONSchemaType<JsonObject>>;
private incomingRequestHandlers: Map<OCPP16IncomingRequestCommand, IncomingRequestHandler>;
- private jsonSchemas: Map<OCPP16IncomingRequestCommand, JSONSchemaType<JsonObject>>;
public constructor() {
if (new.target?.name === moduleName) {
);
}
logger.warn(
- `${chargingStation.logPrefix()} ${moduleName}.validatePayload: No JSON schema found for command ${commandName} PDU validation`
+ `${chargingStation.logPrefix()} ${moduleName}.validatePayload: No JSON schema found for command '${commandName}' PDU validation`
);
return false;
}
import { OCPPVersion } from '../../../types/ocpp/OCPPVersion';
import type { RequestParams } from '../../../types/ocpp/Requests';
import Constants from '../../../utils/Constants';
-import logger from '../../../utils/Logger';
import Utils from '../../../utils/Utils';
import type ChargingStation from '../../ChargingStation';
import OCPPRequestService from '../OCPPRequestService';
const moduleName = 'OCPP16RequestService';
export default class OCPP16RequestService extends OCPPRequestService {
- private jsonSchemas: Map<OCPP16RequestCommand, JSONSchemaType<JsonObject>>;
+ protected jsonSchemas: Map<OCPP16RequestCommand, JSONSchemaType<JsonObject>>;
public constructor(ocppResponseService: OCPPResponseService) {
if (new.target?.name === moduleName) {
);
}
- protected getRequestPayloadValidationSchema(
- chargingStation: ChargingStation,
- commandName: OCPP16RequestCommand
- ): JSONSchemaType<JsonObject> | false {
- if (this.jsonSchemas.has(commandName) === true) {
- return this.jsonSchemas.get(commandName);
- }
- logger.warn(
- `${chargingStation.logPrefix()} ${moduleName}.getPayloadValidationSchema: No JSON schema found for command ${commandName} PDU validation`
- );
- return false;
- }
-
private buildRequestPayload<Request extends JsonType>(
chargingStation: ChargingStation,
commandName: OCPP16RequestCommand,
} from '../../../types/ocpp/1.6/MeterValues';
import {
type OCPP16BootNotificationRequest,
+ OCPP16IncomingRequestCommand,
OCPP16RequestCommand,
type OCPP16StatusNotificationRequest,
} from '../../../types/ocpp/1.6/Requests';
const moduleName = 'OCPP16ResponseService';
export default class OCPP16ResponseService extends OCPPResponseService {
+ public jsonIncomingRequestResponseSchemas: Map<
+ OCPP16IncomingRequestCommand,
+ JSONSchemaType<JsonObject>
+ >;
+
private responseHandlers: Map<OCPP16RequestCommand, ResponseHandler>;
private jsonSchemas: Map<OCPP16RequestCommand, JSONSchemaType<JsonObject>>;
) as JSONSchemaType<OCPP16DataTransferResponse>,
],
]);
+ this.jsonIncomingRequestResponseSchemas = new Map();
this.validatePayload.bind(this);
}
);
}
logger.warn(
- `${chargingStation.logPrefix()} ${moduleName}.validatePayload: No JSON schema found for command ${commandName} PDU validation`
+ `${chargingStation.logPrefix()} ${moduleName}.validatePayload: No JSON schema found for command '${commandName}' PDU validation`
);
return false;
}
const moduleName = 'OCPP20IncomingRequestService';
export default class OCPP20IncomingRequestService extends OCPPIncomingRequestService {
+ protected jsonSchemas: Map<OCPP20IncomingRequestCommand, JSONSchemaType<JsonObject>>;
private incomingRequestHandlers: Map<OCPP20IncomingRequestCommand, IncomingRequestHandler>;
- private jsonSchemas: Map<OCPP20IncomingRequestCommand, JSONSchemaType<JsonObject>>;
public constructor() {
if (new.target?.name === moduleName) {
);
}
logger.warn(
- `${chargingStation.logPrefix()} ${moduleName}.validatePayload: No JSON schema found for command ${commandName} PDU validation`
+ `${chargingStation.logPrefix()} ${moduleName}.validatePayload: No JSON schema found for command '${commandName}' PDU validation`
);
return false;
}
import { ErrorType } from '../../../types/ocpp/ErrorType';
import { OCPPVersion } from '../../../types/ocpp/OCPPVersion';
import type { RequestParams } from '../../../types/ocpp/Requests';
-import logger from '../../../utils/Logger';
import Utils from '../../../utils/Utils';
import type ChargingStation from '../../ChargingStation';
import OCPPRequestService from '../OCPPRequestService';
const moduleName = 'OCPP20RequestService';
export default class OCPP20RequestService extends OCPPRequestService {
- private jsonSchemas: Map<OCPP20RequestCommand, JSONSchemaType<JsonObject>>;
+ protected jsonSchemas: Map<OCPP20RequestCommand, JSONSchemaType<JsonObject>>;
public constructor(ocppResponseService: OCPPResponseService) {
if (new.target?.name === moduleName) {
);
}
- protected getRequestPayloadValidationSchema(
- chargingStation: ChargingStation,
- commandName: OCPP20RequestCommand
- ): JSONSchemaType<JsonObject> | false {
- if (this.jsonSchemas.has(commandName) === true) {
- return this.jsonSchemas.get(commandName);
- }
- logger.warn(
- `${chargingStation.logPrefix()} ${moduleName}.getPayloadValidationSchema: No JSON schema found for command ${commandName} PDU validation`
- );
- return false;
- }
-
private buildRequestPayload<Request extends JsonType>(
chargingStation: ChargingStation,
commandName: OCPP20RequestCommand,
import OCPPError from '../../../exception/OCPPError';
import type { JsonObject, JsonType } from '../../../types/JsonType';
-import { OCPP20RequestCommand } from '../../../types/ocpp/2.0/Requests';
+import {
+ OCPP20IncomingRequestCommand,
+ OCPP20RequestCommand,
+} from '../../../types/ocpp/2.0/Requests';
import type { OCPP20BootNotificationResponse } from '../../../types/ocpp/2.0/Responses';
import { ErrorType } from '../../../types/ocpp/ErrorType';
import { OCPPVersion } from '../../../types/ocpp/OCPPVersion';
const moduleName = 'OCPP20ResponseService';
export default class OCPP20ResponseService extends OCPPResponseService {
+ public jsonIncomingRequestResponseSchemas: Map<
+ OCPP20IncomingRequestCommand,
+ JSONSchemaType<JsonObject>
+ >;
+
private responseHandlers: Map<OCPP20RequestCommand, ResponseHandler>;
private jsonSchemas: Map<OCPP20RequestCommand, JSONSchemaType<JsonObject>>;
) as JSONSchemaType<OCPP20BootNotificationResponse>,
],
]);
+ this.jsonIncomingRequestResponseSchemas = new Map();
this.validatePayload.bind(this);
}
);
}
logger.warn(
- `${chargingStation.logPrefix()} ${moduleName}.validatePayload: No JSON schema found for command ${commandName} PDU validation`
+ `${chargingStation.logPrefix()} ${moduleName}.validatePayload: No JSON schema found for command '${commandName}' PDU validation`
);
return false;
}
import OCPPError from '../../exception/OCPPError';
import type { HandleErrorParams } from '../../types/Error';
-import type { JsonType } from '../../types/JsonType';
+import type { JsonObject, JsonType } from '../../types/JsonType';
import type { OCPPVersion } from '../../types/ocpp/OCPPVersion';
import type { IncomingRequestCommand } from '../../types/ocpp/Requests';
import logger from '../../utils/Logger';
protected asyncResource: AsyncResource;
private readonly version: OCPPVersion;
private readonly ajv: Ajv;
+ protected abstract jsonSchemas: Map<IncomingRequestCommand, JSONSchemaType<JsonObject>>;
protected constructor(version: OCPPVersion) {
this.version = version;
private static instance: OCPPRequestService | null = null;
private readonly version: OCPPVersion;
private readonly ajv: Ajv;
-
private readonly ocppResponseService: OCPPResponseService;
+ protected abstract jsonSchemas: Map<RequestCommand, JSONSchemaType<JsonObject>>;
protected constructor(version: OCPPVersion, ocppResponseService: OCPPResponseService) {
this.version = version;
}
}
- protected validateRequestPayload<T extends JsonType>(
+ protected validateRequestPayload<T extends JsonObject>(
chargingStation: ChargingStation,
commandName: RequestCommand | IncomingRequestCommand,
payload: T
if (chargingStation.getPayloadSchemaValidation() === false) {
return true;
}
- const schema = this.getRequestPayloadValidationSchema(chargingStation, commandName);
- if (schema === false) {
+ if (this.jsonSchemas.has(commandName as RequestCommand) === false) {
+ logger.warn(
+ `${chargingStation.logPrefix()} ${moduleName}.validateRequestPayload: No JSON schema found for command '${commandName}' PDU validation`
+ );
return true;
}
- const validate = this.ajv.compile(schema);
+ const validate = this.ajv.compile(this.jsonSchemas.get(commandName as RequestCommand));
+ payload = Utils.cloneObject<T>(payload);
OCPPServiceUtils.convertDateToISOString<T>(payload);
if (validate(payload)) {
return true;
);
}
+ protected validateResponsePayload<T extends JsonObject>(
+ chargingStation: ChargingStation,
+ commandName: RequestCommand | IncomingRequestCommand,
+ payload: T
+ ): boolean {
+ if (chargingStation.getPayloadSchemaValidation() === false) {
+ return true;
+ }
+ if (
+ this.ocppResponseService.jsonIncomingRequestResponseSchemas.has(
+ commandName as IncomingRequestCommand
+ ) === false
+ ) {
+ logger.warn(
+ `${chargingStation.logPrefix()} ${moduleName}.validateResponsePayload: No JSON schema found for command '${commandName}' PDU validation`
+ );
+ return true;
+ }
+ const validate = this.ajv.compile(
+ this.ocppResponseService.jsonIncomingRequestResponseSchemas.get(
+ commandName as IncomingRequestCommand
+ )
+ );
+ payload = Utils.cloneObject<T>(payload);
+ OCPPServiceUtils.convertDateToISOString<T>(payload);
+ if (validate(payload)) {
+ return true;
+ }
+ logger.error(
+ `${chargingStation.logPrefix()} ${moduleName}.validateResponsePayload: 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().
+ throw new OCPPError(
+ OCPPServiceUtils.ajvErrorsToErrorType(validate.errors),
+ 'Response PDU is invalid',
+ commandName,
+ JSON.stringify(validate.errors, null, 2)
+ );
+ }
+
private async internalSendMessage(
chargingStation: ChargingStation,
messageId: string,
commandName,
messagePayload as JsonType,
]);
- this.validateRequestPayload(chargingStation, commandName, messagePayload as JsonType);
+ this.validateRequestPayload(chargingStation, commandName, messagePayload as JsonObject);
messageToSend = JSON.stringify([
messageType,
messageId,
// Response
case MessageType.CALL_RESULT_MESSAGE:
// Build response
- // FIXME: Validate response payload
+ this.validateResponsePayload(chargingStation, commandName, messagePayload as JsonObject);
messageToSend = JSON.stringify([messageType, messageId, messagePayload] as Response);
break;
// Error Message
commandParams?: JsonType,
params?: RequestParams
): Promise<ResType>;
-
- protected abstract getRequestPayloadValidationSchema(
- chargingStation: ChargingStation,
- commandName: RequestCommand | IncomingRequestCommand
- ): JSONSchemaType<JsonObject> | false;
}
import ajvFormats from 'ajv-formats';
import OCPPError from '../../exception/OCPPError';
-import type { JsonType } from '../../types/JsonType';
+import type { JsonObject, JsonType } from '../../types/JsonType';
import type { OCPPVersion } from '../../types/ocpp/OCPPVersion';
-import type { RequestCommand } from '../../types/ocpp/Requests';
+import type { IncomingRequestCommand, RequestCommand } from '../../types/ocpp/Requests';
import logger from '../../utils/Logger';
import type ChargingStation from '../ChargingStation';
import { OCPPServiceUtils } from './OCPPServiceUtils';
private static instance: OCPPResponseService | null = null;
private readonly version: OCPPVersion;
private readonly ajv: Ajv;
+ public abstract jsonIncomingRequestResponseSchemas: Map<
+ IncomingRequestCommand,
+ JSONSchemaType<JsonObject>
+ >;
protected constructor(version: OCPPVersion) {
this.version = version;