@zetra/citrineos-util 1.8.3-fork.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (142) hide show
  1. package/dist/authorization/ApiAuthPlugin.d.ts +52 -0
  2. package/dist/authorization/ApiAuthPlugin.js +122 -0
  3. package/dist/authorization/ApiAuthPlugin.js.map +1 -0
  4. package/dist/authorization/OidcTokenProvider.d.ts +15 -0
  5. package/dist/authorization/OidcTokenProvider.js +47 -0
  6. package/dist/authorization/OidcTokenProvider.js.map +1 -0
  7. package/dist/authorization/index.d.ts +4 -0
  8. package/dist/authorization/index.js +8 -0
  9. package/dist/authorization/index.js.map +1 -0
  10. package/dist/authorization/provider/LocalByPassAuthProvider.d.ts +34 -0
  11. package/dist/authorization/provider/LocalByPassAuthProvider.js +62 -0
  12. package/dist/authorization/provider/LocalByPassAuthProvider.js.map +1 -0
  13. package/dist/authorization/provider/OIDCAuthProvider.d.ts +62 -0
  14. package/dist/authorization/provider/OIDCAuthProvider.js +173 -0
  15. package/dist/authorization/provider/OIDCAuthProvider.js.map +1 -0
  16. package/dist/authorization/rbac/RbacRulesLoader.d.ts +32 -0
  17. package/dist/authorization/rbac/RbacRulesLoader.js +105 -0
  18. package/dist/authorization/rbac/RbacRulesLoader.js.map +1 -0
  19. package/dist/authorization/rbac/UrlMatcher.d.ts +14 -0
  20. package/dist/authorization/rbac/UrlMatcher.js +44 -0
  21. package/dist/authorization/rbac/UrlMatcher.js.map +1 -0
  22. package/dist/authorizer/RealTimeAuthorizer.d.ts +28 -0
  23. package/dist/authorizer/RealTimeAuthorizer.js +152 -0
  24. package/dist/authorizer/RealTimeAuthorizer.js.map +1 -0
  25. package/dist/authorizer/index.d.ts +1 -0
  26. package/dist/authorizer/index.js +5 -0
  27. package/dist/authorizer/index.js.map +1 -0
  28. package/dist/cache/memory.d.ts +19 -0
  29. package/dist/cache/memory.js +147 -0
  30. package/dist/cache/memory.js.map +1 -0
  31. package/dist/cache/redis.d.ts +16 -0
  32. package/dist/cache/redis.js +120 -0
  33. package/dist/cache/redis.js.map +1 -0
  34. package/dist/certificate/CertificateAuthority.d.ts +38 -0
  35. package/dist/certificate/CertificateAuthority.js +233 -0
  36. package/dist/certificate/CertificateAuthority.js.map +1 -0
  37. package/dist/certificate/CertificateUtil.d.ts +60 -0
  38. package/dist/certificate/CertificateUtil.js +317 -0
  39. package/dist/certificate/CertificateUtil.js.map +1 -0
  40. package/dist/certificate/client/acme.d.ts +37 -0
  41. package/dist/certificate/client/acme.js +138 -0
  42. package/dist/certificate/client/acme.js.map +1 -0
  43. package/dist/certificate/client/hubject.d.ts +41 -0
  44. package/dist/certificate/client/hubject.js +221 -0
  45. package/dist/certificate/client/hubject.js.map +1 -0
  46. package/dist/certificate/client/interface.d.ts +12 -0
  47. package/dist/certificate/client/interface.js +5 -0
  48. package/dist/certificate/client/interface.js.map +1 -0
  49. package/dist/certificate/index.d.ts +2 -0
  50. package/dist/certificate/index.js +6 -0
  51. package/dist/certificate/index.js.map +1 -0
  52. package/dist/files/ftpServer.d.ts +4 -0
  53. package/dist/files/ftpServer.js +9 -0
  54. package/dist/files/ftpServer.js.map +1 -0
  55. package/dist/files/gcpCloudStorage.d.ts +39 -0
  56. package/dist/files/gcpCloudStorage.js +130 -0
  57. package/dist/files/gcpCloudStorage.js.map +1 -0
  58. package/dist/files/localStorage.d.ts +14 -0
  59. package/dist/files/localStorage.js +57 -0
  60. package/dist/files/localStorage.js.map +1 -0
  61. package/dist/files/s3Storage.d.ts +17 -0
  62. package/dist/files/s3Storage.js +118 -0
  63. package/dist/files/s3Storage.js.map +1 -0
  64. package/dist/index.d.ts +21 -0
  65. package/dist/index.js +25 -0
  66. package/dist/index.js.map +1 -0
  67. package/dist/networkconnection/WebsocketNetworkConnection.d.ts +135 -0
  68. package/dist/networkconnection/WebsocketNetworkConnection.js +474 -0
  69. package/dist/networkconnection/WebsocketNetworkConnection.js.map +1 -0
  70. package/dist/networkconnection/authenticator/Authenticator.d.ts +20 -0
  71. package/dist/networkconnection/authenticator/Authenticator.js +39 -0
  72. package/dist/networkconnection/authenticator/Authenticator.js.map +1 -0
  73. package/dist/networkconnection/authenticator/AuthenticatorFilter.d.ts +11 -0
  74. package/dist/networkconnection/authenticator/AuthenticatorFilter.js +30 -0
  75. package/dist/networkconnection/authenticator/AuthenticatorFilter.js.map +1 -0
  76. package/dist/networkconnection/authenticator/BasicAuthenticationFilter.d.ts +17 -0
  77. package/dist/networkconnection/authenticator/BasicAuthenticationFilter.js +51 -0
  78. package/dist/networkconnection/authenticator/BasicAuthenticationFilter.js.map +1 -0
  79. package/dist/networkconnection/authenticator/ConnectedStationFilter.d.ts +14 -0
  80. package/dist/networkconnection/authenticator/ConnectedStationFilter.js +25 -0
  81. package/dist/networkconnection/authenticator/ConnectedStationFilter.js.map +1 -0
  82. package/dist/networkconnection/authenticator/NetworkProfileFilter.d.ts +16 -0
  83. package/dist/networkconnection/authenticator/NetworkProfileFilter.js +84 -0
  84. package/dist/networkconnection/authenticator/NetworkProfileFilter.js.map +1 -0
  85. package/dist/networkconnection/authenticator/UnknownStationFilter.d.ts +16 -0
  86. package/dist/networkconnection/authenticator/UnknownStationFilter.js +25 -0
  87. package/dist/networkconnection/authenticator/UnknownStationFilter.js.map +1 -0
  88. package/dist/networkconnection/authenticator/errors/AuthenticationError.d.ts +6 -0
  89. package/dist/networkconnection/authenticator/errors/AuthenticationError.js +25 -0
  90. package/dist/networkconnection/authenticator/errors/AuthenticationError.js.map +1 -0
  91. package/dist/networkconnection/authenticator/errors/IUpgradeError.d.ts +9 -0
  92. package/dist/networkconnection/authenticator/errors/IUpgradeError.js +5 -0
  93. package/dist/networkconnection/authenticator/errors/IUpgradeError.js.map +1 -0
  94. package/dist/networkconnection/authenticator/errors/UnknownError.d.ts +6 -0
  95. package/dist/networkconnection/authenticator/errors/UnknownError.js +24 -0
  96. package/dist/networkconnection/authenticator/errors/UnknownError.js.map +1 -0
  97. package/dist/networkconnection/index.d.ts +5 -0
  98. package/dist/networkconnection/index.js +9 -0
  99. package/dist/networkconnection/index.js.map +1 -0
  100. package/dist/queue/index.d.ts +4 -0
  101. package/dist/queue/index.js +8 -0
  102. package/dist/queue/index.js.map +1 -0
  103. package/dist/queue/kafka/receiver.d.ts +35 -0
  104. package/dist/queue/kafka/receiver.js +179 -0
  105. package/dist/queue/kafka/receiver.js.map +1 -0
  106. package/dist/queue/kafka/sender.d.ts +53 -0
  107. package/dist/queue/kafka/sender.js +189 -0
  108. package/dist/queue/kafka/sender.js.map +1 -0
  109. package/dist/queue/rabbit-mq/receiver.d.ts +89 -0
  110. package/dist/queue/rabbit-mq/receiver.js +472 -0
  111. package/dist/queue/rabbit-mq/receiver.js.map +1 -0
  112. package/dist/queue/rabbit-mq/sender.d.ts +90 -0
  113. package/dist/queue/rabbit-mq/sender.js +251 -0
  114. package/dist/queue/rabbit-mq/sender.js.map +1 -0
  115. package/dist/security/SignedMeterValuesUtil.d.ts +44 -0
  116. package/dist/security/SignedMeterValuesUtil.js +135 -0
  117. package/dist/security/SignedMeterValuesUtil.js.map +1 -0
  118. package/dist/security/authentication.d.ts +2 -0
  119. package/dist/security/authentication.js +26 -0
  120. package/dist/security/authentication.js.map +1 -0
  121. package/dist/util/RequestOperations.d.ts +14 -0
  122. package/dist/util/RequestOperations.js +25 -0
  123. package/dist/util/RequestOperations.js.map +1 -0
  124. package/dist/util/StringOperations.d.ts +1 -0
  125. package/dist/util/StringOperations.js +8 -0
  126. package/dist/util/StringOperations.js.map +1 -0
  127. package/dist/util/emaidCheckDigitCalculator.d.ts +15 -0
  128. package/dist/util/emaidCheckDigitCalculator.js +179 -0
  129. package/dist/util/emaidCheckDigitCalculator.js.map +1 -0
  130. package/dist/util/idGenerator.d.ts +7 -0
  131. package/dist/util/idGenerator.js +10 -0
  132. package/dist/util/idGenerator.js.map +1 -0
  133. package/dist/util/parser.d.ts +31 -0
  134. package/dist/util/parser.js +60 -0
  135. package/dist/util/parser.js.map +1 -0
  136. package/dist/util/swagger.d.ts +5 -0
  137. package/dist/util/swagger.js +154 -0
  138. package/dist/util/swagger.js.map +1 -0
  139. package/dist/util/validator.d.ts +110 -0
  140. package/dist/util/validator.js +534 -0
  141. package/dist/util/validator.js.map +1 -0
  142. package/package.json +46 -0
@@ -0,0 +1,474 @@
1
+ import { CacheNamespace, createIdentifier, getStationIdFromIdentifier, getTenantIdFromIdentifier, } from '@citrineos/base';
2
+ import fs from 'fs';
3
+ import * as http from 'http';
4
+ import * as https from 'https';
5
+ import { Duplex } from 'stream';
6
+ import { Logger } from 'tslog';
7
+ import { WebSocket, WebSocketServer } from 'ws';
8
+ export class WebsocketNetworkConnection {
9
+ _cache;
10
+ _config;
11
+ _logger;
12
+ _identifierConnections = new Map();
13
+ // websocketServers id as key and http server as value
14
+ _httpServersMap;
15
+ _authenticator;
16
+ _router;
17
+ _doesChargingStationExistByStationId;
18
+ constructor(config, cache, authenticator, router, logger, doesChargingStationExistByStationId) {
19
+ this._cache = cache;
20
+ this._config = config;
21
+ this._doesChargingStationExistByStationId = doesChargingStationExistByStationId;
22
+ this._logger = logger
23
+ ? logger.getSubLogger({ name: this.constructor.name })
24
+ : new Logger({ name: this.constructor.name });
25
+ this._authenticator = authenticator;
26
+ router.networkHook = this.sendMessage.bind(this);
27
+ this._router = router;
28
+ this._httpServersMap = new Map();
29
+ this._config.util.networkConnection.websocketServers.forEach(async (websocketServerConfig) => {
30
+ const _httpServer = await this._createAndStartWebsocketServer(websocketServerConfig);
31
+ this._httpServersMap.set(websocketServerConfig.id, _httpServer);
32
+ });
33
+ }
34
+ /**
35
+ * Send a message to the charging station specified by the identifier.
36
+ *
37
+ * @param {string} identifier - The identifier of the client.
38
+ * @param {string} message - The message to send.
39
+ * @return {void} rejects the promise if message fails to send, otherwise returns void.
40
+ */
41
+ sendMessage(identifier, message) {
42
+ return new Promise(async (resolve, reject) => {
43
+ try {
44
+ const clientConnection = await this._cache.get(identifier, CacheNamespace.Connections);
45
+ if (clientConnection) {
46
+ const websocketConnection = this._identifierConnections.get(identifier);
47
+ if (websocketConnection && websocketConnection.readyState === WebSocket.OPEN) {
48
+ websocketConnection.send(message, (error) => {
49
+ if (error) {
50
+ reject(error); // Reject the promise with the error
51
+ }
52
+ else {
53
+ resolve(); // Resolve the promise with true indicating success
54
+ }
55
+ });
56
+ }
57
+ else {
58
+ const errorMsg = 'Websocket connection is not ready - ' + identifier;
59
+ this._logger.fatal(errorMsg);
60
+ websocketConnection?.close(1011, errorMsg);
61
+ reject(new Error(errorMsg)); // Reject with a new error
62
+ }
63
+ }
64
+ else {
65
+ const errorMsg = 'Cannot identify client connection for ' + identifier;
66
+ // This can happen when a charging station disconnects in the moment a message is trying to send.
67
+ // Retry logic on the message sender might not suffice as charging station might connect to different instance.
68
+ this._logger.error(errorMsg);
69
+ this._identifierConnections
70
+ .get(identifier)
71
+ ?.close(1011, 'Failed to get connection information for ' + identifier);
72
+ reject(new Error(errorMsg)); // Reject with a new error
73
+ }
74
+ }
75
+ catch (error) {
76
+ reject(error);
77
+ }
78
+ });
79
+ }
80
+ bindNetworkHook() {
81
+ return (identifier, message) => this.sendMessage(identifier, message);
82
+ }
83
+ async disconnect(tenantId, stationId) {
84
+ const identifier = createIdentifier(tenantId, stationId);
85
+ const websocketConnection = this._identifierConnections.get(identifier);
86
+ if (!websocketConnection) {
87
+ this._logger.warn(`No websocket connection found for tenantId ${tenantId} and stationId ${stationId}, will still deregister from router.`);
88
+ }
89
+ websocketConnection?.close(1000, 'Disconnected by admin request');
90
+ const deregistered = await this._router?.deregisterConnection(tenantId, stationId);
91
+ return !!websocketConnection && deregistered;
92
+ }
93
+ async shutdown() {
94
+ this._httpServersMap.forEach((server) => server.close());
95
+ }
96
+ /**
97
+ * Updates certificates for a specific server with the provided TLS key, certificate chain, and optional
98
+ * root CA.
99
+ *
100
+ * @param {string} serverId - The ID of the server to update.
101
+ * @param {string} tlsKey - The TLS key to set.
102
+ * @param {string} tlsCertificateChain - The TLS certificate chain to set.
103
+ * @param {string} [rootCA] - The root CA to set (optional).
104
+ * @return {void} void
105
+ */
106
+ updateTlsCertificates(serverId, tlsKey, tlsCertificateChain, rootCA) {
107
+ let httpsServer = this._httpServersMap.get(serverId);
108
+ if (httpsServer && httpsServer instanceof https.Server) {
109
+ const secureContextOptions = {
110
+ key: tlsKey,
111
+ cert: tlsCertificateChain,
112
+ };
113
+ if (rootCA) {
114
+ secureContextOptions.ca = rootCA;
115
+ }
116
+ httpsServer.setSecureContext(secureContextOptions);
117
+ this._logger.info(`Updated TLS certificates in SecureContextOptions for server ${serverId}`);
118
+ }
119
+ else {
120
+ throw new TypeError(`Server ${serverId} is not a https server.`);
121
+ }
122
+ }
123
+ /**
124
+ * Dynamically adds a new websocket server at runtime and starts it.
125
+ *
126
+ * @param {WebsocketServerConfig} websocketServerConfig
127
+ * @returns {Promise<void>}
128
+ */
129
+ async addWebsocketServer(websocketServerConfig) {
130
+ const httpServer = await this._createAndStartWebsocketServer(websocketServerConfig);
131
+ this._httpServersMap.set(websocketServerConfig.id, httpServer);
132
+ }
133
+ _onHttpRequest(req, res) {
134
+ if (req.method === 'GET' && req.url === '/health') {
135
+ res.writeHead(200, { 'Content-Type': 'application/json' });
136
+ res.end(JSON.stringify({ status: 'healthy' }));
137
+ }
138
+ else {
139
+ res.writeHead(404, { 'Content-Type': 'application/json' });
140
+ res.end(JSON.stringify({
141
+ message: `Route ${req.method}:${req.url} not found`,
142
+ error: 'Not Found',
143
+ statusCode: 404,
144
+ }));
145
+ }
146
+ }
147
+ /**
148
+ * Method to validate websocket upgrade requests and pass them to the socket server.
149
+ *
150
+ * @param {IncomingMessage} req - The request object.
151
+ * @param {Duplex} socket - Websocket duplex stream.
152
+ * @param {Buffer} head - Websocket buffer.
153
+ * @param {WebSocketServer} wss - Websocket server.
154
+ * @param {WebsocketServerConfig} websocketServerConfig - websocket server config.
155
+ */
156
+ async _upgradeRequest(req, socket, head, wss, websocketServerConfig) {
157
+ // Failed mTLS and TLS requests are rejected by the server before getting this far
158
+ this._logger.debug('On upgrade request', req.method, req.url, req.headers, websocketServerConfig);
159
+ try {
160
+ // Resolve tenant at upgrade time (query param, path segment, header),
161
+ // falling back to the server-configured tenant if none provided.
162
+ const resolvedTenantId = websocketServerConfig.dynamicTenantResolution
163
+ ? this._extractTenantIdFromRequest(req, websocketServerConfig) ??
164
+ websocketServerConfig.tenantId
165
+ : websocketServerConfig.tenantId;
166
+ // Attach resolved tenant to request so downstream handlers (connection) can use it
167
+ req.__resolvedTenantId = resolvedTenantId;
168
+ const { identifier } = await this._authenticator.authenticate(req, resolvedTenantId, {
169
+ securityProfile: websocketServerConfig.securityProfile,
170
+ allowUnknownChargingStations: websocketServerConfig.allowUnknownChargingStations,
171
+ });
172
+ this._logger.debug('Successfully registered websocket client', identifier);
173
+ wss.handleUpgrade(req, socket, head, (ws) => {
174
+ wss.emit('connection', ws, req);
175
+ });
176
+ }
177
+ catch (error) {
178
+ /**
179
+ * See {@link IUpgradeError.terminateConnection}
180
+ **/
181
+ error?.terminateConnection?.(socket) || this._terminateConnectionInternalError(socket);
182
+ this._logger.warn(error);
183
+ }
184
+ }
185
+ /**
186
+ * Utility function to reject websocket upgrade requests with 500 status code.
187
+ * @param socket - Websocket duplex stream.
188
+ */
189
+ _terminateConnectionInternalError(socket) {
190
+ socket.write('HTTP/1.1 500 Internal Server Error\r\n');
191
+ socket.write('\r\n');
192
+ socket.end();
193
+ socket.destroy();
194
+ }
195
+ /**
196
+ * Internal method to handle new client connection and ensures supported protocols are used.
197
+ *
198
+ * @param {Set<string>} protocols - The set of protocols to handle.
199
+ * @param {IncomingMessage} _req - The request object.
200
+ * @param {string} wsServerProtocol - The websocket server protocol.
201
+ * @return {boolean|string} - Returns the protocol version if successful, otherwise false.
202
+ */
203
+ _handleProtocols(protocols, _req, wsServerProtocol) {
204
+ // Only supports configured protocol version
205
+ if (protocols.has(wsServerProtocol)) {
206
+ return wsServerProtocol;
207
+ }
208
+ this._logger.error(`Protocol mismatch. Charger supports: [${[...protocols].join(', ')}], but server expects: '${wsServerProtocol}'.`);
209
+ // Reject the client trying to connect
210
+ return false;
211
+ }
212
+ /**
213
+ * Internal method to handle the connection event when a WebSocket connection is established.
214
+ * This happens after successful protocol exchange with client.
215
+ *
216
+ * @param {WebSocket} ws - The WebSocket object representing the connection.
217
+ * @param {WebsocketServerConfig} websocketServerConfig - The websocket server configuration.
218
+ * @param {number} pingInterval - The ping interval in seconds.
219
+ * @param {IncomingMessage} req - The request object associated with the connection.
220
+ * @return {void}
221
+ */
222
+ async _onConnection(ws, websocketServerConfig, pingInterval, req) {
223
+ if (!ws.protocol) {
224
+ this._logger.debug('Websocket connection without protocol');
225
+ return;
226
+ }
227
+ else {
228
+ // Pause the WebSocket event emitter until broker is established
229
+ ws.pause();
230
+ const stationId = this._getClientIdFromUrl(req.url);
231
+ // Prefer tenant resolved during upgrade; fallback to server-configured tenant.
232
+ const tenantId = req.__resolvedTenantId ?? websocketServerConfig.tenantId;
233
+ const checker = this._doesChargingStationExistByStationId ??
234
+ this._router.doesChargingStationExistByStationId?.bind(this._router);
235
+ if (!checker) {
236
+ throw new Error('No method available to check if charging station exists');
237
+ }
238
+ const exists = await checker(tenantId, stationId);
239
+ if (!exists && !websocketServerConfig.allowUnknownChargingStations) {
240
+ this._logger.error('Rejecting connection: station %s not found in tenant %s', stationId, tenantId);
241
+ ws.close(1011, 'Unknown charging station');
242
+ return;
243
+ }
244
+ const identifier = createIdentifier(tenantId, stationId);
245
+ // Enforce optional per-tenant connection limit if configured
246
+ const maxConnections = websocketServerConfig.maxConnectionsPerTenant;
247
+ if (typeof maxConnections === 'number' && maxConnections > 0) {
248
+ const currentCount = [...this._identifierConnections.keys()].filter((k) => getTenantIdFromIdentifier(k) === tenantId).length;
249
+ if (currentCount >= maxConnections) {
250
+ this._logger.warn(`Tenant ${tenantId} exceeded max connections (${maxConnections}), rejecting ${identifier}`);
251
+ ws.close(1013, 'Tenant connection limit exceeded');
252
+ return;
253
+ }
254
+ }
255
+ this._identifierConnections.set(identifier, ws);
256
+ try {
257
+ // Get IP address of client
258
+ const ip = req.headers['x-forwarded-for']?.toString().split(',')[0].trim() ||
259
+ req.socket.remoteAddress ||
260
+ 'N/A';
261
+ const port = req.socket.remotePort;
262
+ const connLogger = this._logger.getSubLogger({
263
+ name: `T${tenantId}:${stationId}`,
264
+ });
265
+ connLogger.info('Client websocket connected', identifier, ip, port, ws.protocol);
266
+ // Register client
267
+ const websocketConnection = {
268
+ id: websocketServerConfig.id,
269
+ protocol: ws.protocol,
270
+ };
271
+ let registered = await this._cache.set(identifier, JSON.stringify(websocketConnection), CacheNamespace.Connections);
272
+ registered =
273
+ registered && (await this._router.registerConnection(tenantId, stationId, ws.protocol));
274
+ if (!registered) {
275
+ connLogger.fatal('Failed to register websocket client', identifier);
276
+ throw new Error('Failed to register websocket client');
277
+ }
278
+ connLogger.info('Successfully connected new charging station.', identifier);
279
+ // Register all websocket events
280
+ this._registerWebsocketEvents(identifier, ws, pingInterval);
281
+ // Resume the WebSocket event emitter after events have been subscribed to
282
+ ws.resume();
283
+ }
284
+ catch (error) {
285
+ this._logger.fatal('Failed to subscribe to message broker for ', identifier);
286
+ ws.close(1011, 'Failed to subscribe to message broker for ' + identifier);
287
+ }
288
+ }
289
+ }
290
+ /**
291
+ * Internal method to register event listeners for the WebSocket connection.
292
+ *
293
+ * @param {string} identifier - The unique identifier of the connection, i.e. the combination of tenantId and stationId.
294
+ * @param {WebSocket} ws - The WebSocket object representing the connection.
295
+ * @param {number} pingInterval - The ping interval in seconds.
296
+ * @return {void} This function does not return anything.
297
+ */
298
+ _registerWebsocketEvents(identifier, ws, pingInterval) {
299
+ ws.onerror = (event) => {
300
+ this._logger.error('Connection error encountered for', identifier, event.error, event.message, event.type);
301
+ ws.close(1011, event.message);
302
+ };
303
+ ws.onmessage = (event) => {
304
+ this._onMessage(identifier, event.data.toString(), ws.protocol);
305
+ };
306
+ ws.once('close', () => {
307
+ // Unregister client
308
+ this._logger.info('Connection closed for', identifier);
309
+ this._cache.remove(identifier, CacheNamespace.Connections);
310
+ this._identifierConnections.delete(identifier);
311
+ this._router.deregisterConnection(getTenantIdFromIdentifier(identifier), getStationIdFromIdentifier(identifier));
312
+ });
313
+ ws.on('ping', async (message) => {
314
+ this._logger.debug(`Ping received for ${identifier} with message ${JSON.stringify(message)}`);
315
+ ws.pong(message);
316
+ });
317
+ ws.on('pong', async () => {
318
+ this._logger.debug('Pong received for', identifier);
319
+ const clientConnection = await this._cache.get(identifier, CacheNamespace.Connections);
320
+ if (clientConnection) {
321
+ // Remove expiration for connection and send ping to client in pingInterval seconds.
322
+ await this._cache.set(identifier, clientConnection, CacheNamespace.Connections);
323
+ this._ping(identifier, ws, pingInterval);
324
+ }
325
+ else {
326
+ this._logger.debug('Pong received for', identifier, 'but client is not alive');
327
+ ws.close(1011, 'Client is not alive');
328
+ }
329
+ });
330
+ this._ping(identifier, ws, pingInterval);
331
+ }
332
+ /**
333
+ * Internal method to handle the incoming message from the websocket client.
334
+ *
335
+ * @param {string} identifier - The client identifier.
336
+ * @param {string} message - The incoming message from the client.
337
+ * @param {OCPPVersionType} protocol - The OCPP protocol version of the client, 'ocpp1.6' or 'ocpp2.0.1'.
338
+ * @return {void} This function does not return anything.
339
+ */
340
+ _onMessage(identifier, message, protocol) {
341
+ this._router.onMessage(identifier, message, new Date(), protocol);
342
+ }
343
+ /**
344
+ * Internal method to handle the error event for the WebSocket server.
345
+ *
346
+ * @param {WebSocketServer} wss - The WebSocket server instance.
347
+ * @param {Error} error - The error object.
348
+ * @return {void} This function does not return anything.
349
+ */
350
+ _onError(wss, error) {
351
+ this._logger.error(error);
352
+ // TODO: Try to recover the Websocket server
353
+ }
354
+ /**
355
+ * Internal method to handle the event when the WebSocketServer is closed.
356
+ *
357
+ * @param {WebSocketServer} wss - The WebSocketServer instance.
358
+ * @return {void} This function does not return anything.
359
+ */
360
+ _onClose(wss) {
361
+ this._logger.debug('Websocket Server closed');
362
+ // TODO: Try to recover the Websocket server
363
+ }
364
+ /**
365
+ * Internal method to execute a ping operation on a WebSocket connection after a delay of 60 seconds.
366
+ *
367
+ * @param {string} identifier - The identifier of the client connection.
368
+ * @param {WebSocket} ws - The WebSocket connection to ping.
369
+ * @param {number} pingInterval - The ping interval in milliseconds.
370
+ * @return {void} This function does not return anything.
371
+ */
372
+ async _ping(identifier, ws, pingInterval) {
373
+ setTimeout(async () => {
374
+ const clientConnection = await this._cache.get(identifier, CacheNamespace.Connections);
375
+ if (clientConnection) {
376
+ this._logger.debug('Pinging client', identifier);
377
+ // Set connection expiration and send ping to client
378
+ await this._cache.set(identifier, clientConnection, CacheNamespace.Connections, pingInterval * 2);
379
+ ws.ping();
380
+ }
381
+ else {
382
+ ws.close(1011, 'Client is not alive');
383
+ }
384
+ }, pingInterval * 1000);
385
+ }
386
+ /**
387
+ *
388
+ * @param url Http upgrade request url used by charger
389
+ * @returns Charger identifier
390
+ */
391
+ _getClientIdFromUrl(url) {
392
+ // Remove query string first
393
+ const pathOnly = url.split('?')[0];
394
+ return pathOnly.split('/').pop();
395
+ }
396
+ /**
397
+ * Extract tenant id from the incoming upgrade request.
398
+ * Supported sources (in order): query `tenant`/`tenantId`, header `x-tenant-id`,
399
+ * path segment (second-last segment if URL is `/tenant/station`).
400
+ */
401
+ _extractTenantIdFromRequest(req, config) {
402
+ try {
403
+ const rawUrl = req.url ?? '';
404
+ const url = new URL(rawUrl, 'http://localhost');
405
+ const segments = url.pathname.split('/').filter(Boolean);
406
+ // Path segment mapping: assume /.../{pathSegment}/{station}
407
+ // We look for a mapping of pathSegment to tenantId.
408
+ if (segments.length >= 2 && config.tenantPathMapping) {
409
+ const pathSegment = segments[segments.length - 2];
410
+ if (config.tenantPathMapping[pathSegment]) {
411
+ return config.tenantPathMapping[pathSegment];
412
+ }
413
+ else {
414
+ this._logger.debug(`No mapping found for path segment: ${pathSegment}`);
415
+ }
416
+ }
417
+ }
418
+ catch (err) {
419
+ // If parsing fails, ignore and fall back to server-configured tenant
420
+ this._logger.debug('Failed to extract tenant from request', err);
421
+ }
422
+ return undefined;
423
+ }
424
+ _generateServerOptions(config) {
425
+ const serverOptions = {
426
+ key: fs.readFileSync(config.tlsKeyFilePath),
427
+ cert: fs.readFileSync(config.tlsCertificateChainFilePath),
428
+ };
429
+ if (config.rootCACertificateFilePath) {
430
+ serverOptions.ca = fs.readFileSync(config.rootCACertificateFilePath);
431
+ }
432
+ if (config.securityProfile > 2) {
433
+ serverOptions.requestCert = true;
434
+ serverOptions.rejectUnauthorized = true;
435
+ }
436
+ else {
437
+ serverOptions.rejectUnauthorized = false;
438
+ }
439
+ return serverOptions;
440
+ }
441
+ _createAndStartWebsocketServer(wsConfig) {
442
+ return new Promise((resolve) => {
443
+ let httpServer;
444
+ switch (wsConfig.securityProfile) {
445
+ case 3: // mTLS
446
+ case 2: // TLS
447
+ httpServer = https.createServer(this._generateServerOptions(wsConfig), this._onHttpRequest.bind(this));
448
+ break;
449
+ case 1:
450
+ case 0:
451
+ default:
452
+ httpServer = http.createServer(this._onHttpRequest.bind(this));
453
+ break;
454
+ }
455
+ const wss = new WebSocketServer({
456
+ noServer: true,
457
+ handleProtocols: (protocols, req) => this._handleProtocols(protocols, req, wsConfig.protocol),
458
+ clientTracking: false,
459
+ });
460
+ wss.on('connection', (ws, req) => this._onConnection(ws, wsConfig, wsConfig.pingInterval, req));
461
+ wss.on('error', (server, error) => this._onError(server, error));
462
+ wss.on('close', (server) => this._onClose(server));
463
+ httpServer.on('upgrade', (req, socket, head) => this._upgradeRequest(req, socket, head, wss, wsConfig));
464
+ httpServer.on('error', (error) => wss.emit('error', error));
465
+ httpServer.on('close', () => wss.emit('close'));
466
+ const protocol = wsConfig.securityProfile > 1 ? 'wss' : 'ws';
467
+ httpServer.listen(wsConfig.port, wsConfig.host, () => {
468
+ this._logger.info(`WebsocketServer running on ${protocol}://${wsConfig.host}:${wsConfig.port}/`);
469
+ resolve(httpServer);
470
+ });
471
+ });
472
+ }
473
+ }
474
+ //# sourceMappingURL=WebsocketNetworkConnection.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WebsocketNetworkConnection.js","sourceRoot":"","sources":["../../src/networkconnection/WebsocketNetworkConnection.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ import type { AuthenticationOptions, IAuthenticator } from '@citrineos/base';
2
+ import type { ILogObj } from 'tslog';
3
+ import { Logger } from 'tslog';
4
+ import { IncomingMessage } from 'http';
5
+ import { UnknownStationFilter } from './UnknownStationFilter.js';
6
+ import { BasicAuthenticationFilter } from './BasicAuthenticationFilter.js';
7
+ import { ConnectedStationFilter } from './ConnectedStationFilter.js';
8
+ import { NetworkProfileFilter } from './NetworkProfileFilter.js';
9
+ export declare class Authenticator implements IAuthenticator {
10
+ protected _logger: Logger<ILogObj>;
11
+ private _unknownStationFilter;
12
+ private _connectedStationFilter;
13
+ private _networkProfileFilter;
14
+ private _basicAuthenticationFilter;
15
+ constructor(unknownStationFilter: UnknownStationFilter, connectedStationFilter: ConnectedStationFilter, networkProfileFilter: NetworkProfileFilter, basicAuthenticationFilter: BasicAuthenticationFilter, logger?: Logger<ILogObj>);
16
+ authenticate(request: IncomingMessage, tenantId: number, options: AuthenticationOptions): Promise<{
17
+ identifier: string;
18
+ }>;
19
+ private _getClientIdFromUrl;
20
+ }
@@ -0,0 +1,39 @@
1
+ // SPDX-FileCopyrightText: 2025 Contributors to the CitrineOS Project
2
+ //
3
+ // SPDX-License-Identifier: Apache-2.0
4
+ import { Logger } from 'tslog';
5
+ import { IncomingMessage } from 'http';
6
+ import { UnknownStationFilter } from './UnknownStationFilter.js';
7
+ import { BasicAuthenticationFilter } from './BasicAuthenticationFilter.js';
8
+ import { ConnectedStationFilter } from './ConnectedStationFilter.js';
9
+ import { NetworkProfileFilter } from './NetworkProfileFilter.js';
10
+ export class Authenticator {
11
+ _logger;
12
+ _unknownStationFilter;
13
+ _connectedStationFilter;
14
+ _networkProfileFilter;
15
+ _basicAuthenticationFilter;
16
+ constructor(unknownStationFilter, connectedStationFilter, networkProfileFilter, basicAuthenticationFilter, logger) {
17
+ this._unknownStationFilter = unknownStationFilter;
18
+ this._connectedStationFilter = connectedStationFilter;
19
+ this._networkProfileFilter = networkProfileFilter;
20
+ this._basicAuthenticationFilter = basicAuthenticationFilter;
21
+ this._logger = logger
22
+ ? logger.getSubLogger({ name: this.constructor.name })
23
+ : new Logger({ name: this.constructor.name });
24
+ }
25
+ async authenticate(request, tenantId, options) {
26
+ const identifier = this._getClientIdFromUrl(request.url);
27
+ this._logger.debug(`Starting authentication for identifier: ${identifier}`);
28
+ await this._unknownStationFilter.authenticate(tenantId, identifier, request, options);
29
+ await this._connectedStationFilter.authenticate(tenantId, identifier, request, options);
30
+ await this._networkProfileFilter.authenticate(tenantId, identifier, request, options);
31
+ await this._basicAuthenticationFilter.authenticate(tenantId, identifier, request, options);
32
+ this._logger.debug(`Authentication successful for identifier: ${identifier}`);
33
+ return { identifier };
34
+ }
35
+ _getClientIdFromUrl(url) {
36
+ return url.split('/').pop();
37
+ }
38
+ }
39
+ //# sourceMappingURL=Authenticator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Authenticator.js","sourceRoot":"","sources":["../../../src/networkconnection/authenticator/Authenticator.ts"],"names":[],"mappings":"AAAA,qEAAqE;AACrE,EAAE;AACF,sCAAsC;AAItC,OAAO,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AAC/B,OAAO,EAAE,eAAe,EAAE,MAAM,MAAM,CAAC;AACvC,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AACjE,OAAO,EAAE,yBAAyB,EAAE,MAAM,gCAAgC,CAAC;AAC3E,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AACrE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AAEjE,MAAM,OAAO,aAAa;IACd,OAAO,CAAkB;IAC3B,qBAAqB,CAAuB;IAC5C,uBAAuB,CAAyB;IAChD,qBAAqB,CAAuB;IAC5C,0BAA0B,CAA4B;IAE9D,YACE,oBAA0C,EAC1C,sBAA8C,EAC9C,oBAA0C,EAC1C,yBAAoD,EACpD,MAAwB;QAExB,IAAI,CAAC,qBAAqB,GAAG,oBAAoB,CAAC;QAClD,IAAI,CAAC,uBAAuB,GAAG,sBAAsB,CAAC;QACtD,IAAI,CAAC,qBAAqB,GAAG,oBAAoB,CAAC;QAClD,IAAI,CAAC,0BAA0B,GAAG,yBAAyB,CAAC;QAC5D,IAAI,CAAC,OAAO,GAAG,MAAM;YACnB,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC;YACtD,CAAC,CAAC,IAAI,MAAM,CAAU,EAAE,IAAI,EAAE,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC,CAAC;IAC3D,CAAC;IAED,KAAK,CAAC,YAAY,CAChB,OAAwB,EACxB,QAAgB,EAChB,OAA8B;QAE9B,MAAM,UAAU,GAAG,IAAI,CAAC,mBAAmB,CAAC,OAAO,CAAC,GAAa,CAAC,CAAC;QACnE,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,2CAA2C,UAAU,EAAE,CAAC,CAAC;QAE5E,MAAM,IAAI,CAAC,qBAAqB,CAAC,YAAY,CAAC,QAAQ,EAAE,UAAU,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;QACtF,MAAM,IAAI,CAAC,uBAAuB,CAAC,YAAY,CAAC,QAAQ,EAAE,UAAU,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;QACxF,MAAM,IAAI,CAAC,qBAAqB,CAAC,YAAY,CAAC,QAAQ,EAAE,UAAU,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;QACtF,MAAM,IAAI,CAAC,0BAA0B,CAAC,YAAY,CAAC,QAAQ,EAAE,UAAU,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;QAE3F,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,6CAA6C,UAAU,EAAE,CAAC,CAAC;QAC9E,OAAO,EAAE,UAAU,EAAE,CAAC;IACxB,CAAC;IAEO,mBAAmB,CAAC,GAAW;QACrC,OAAO,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAY,CAAC;IACxC,CAAC;CACF"}
@@ -0,0 +1,11 @@
1
+ import { IncomingMessage } from 'http';
2
+ import type { ILogObj } from 'tslog';
3
+ import { Logger } from 'tslog';
4
+ import type { AuthenticationOptions } from '@citrineos/base';
5
+ export declare abstract class AuthenticatorFilter {
6
+ protected _logger: Logger<ILogObj>;
7
+ protected constructor(logger?: Logger<ILogObj>);
8
+ protected abstract shouldFilter(options: AuthenticationOptions): boolean;
9
+ protected abstract filter(tenantId: number, identifier: string, request: IncomingMessage, options?: AuthenticationOptions): Promise<void>;
10
+ authenticate(tenantId: number, identifier: string, request: IncomingMessage, options: AuthenticationOptions): Promise<void>;
11
+ }
@@ -0,0 +1,30 @@
1
+ // SPDX-FileCopyrightText: 2025 Contributors to the CitrineOS Project
2
+ //
3
+ // SPDX-License-Identifier: Apache-2.0
4
+ import { IncomingMessage } from 'http';
5
+ import { Logger } from 'tslog';
6
+ export class AuthenticatorFilter {
7
+ _logger;
8
+ constructor(logger) {
9
+ this._logger = logger
10
+ ? logger.getSubLogger({ name: this.constructor.name })
11
+ : new Logger({ name: this.constructor.name });
12
+ }
13
+ async authenticate(tenantId, identifier, request, options) {
14
+ if (this.shouldFilter(options)) {
15
+ this._logger.debug(`Applying filter for: ${identifier}`);
16
+ try {
17
+ await this.filter(tenantId, identifier, request, options);
18
+ this._logger.debug(`Filter passed for: ${identifier}`);
19
+ }
20
+ catch (error) {
21
+ this._logger.warn(`Filter failed for: ${identifier}`);
22
+ throw error;
23
+ }
24
+ }
25
+ else {
26
+ this._logger.debug(`Filter skipped for: ${identifier}`);
27
+ }
28
+ }
29
+ }
30
+ //# sourceMappingURL=AuthenticatorFilter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AuthenticatorFilter.js","sourceRoot":"","sources":["../../../src/networkconnection/authenticator/AuthenticatorFilter.ts"],"names":[],"mappings":"AAAA,qEAAqE;AACrE,EAAE;AACF,sCAAsC;AACtC,OAAO,EAAE,eAAe,EAAE,MAAM,MAAM,CAAC;AAEvC,OAAO,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AAG/B,MAAM,OAAgB,mBAAmB;IAC7B,OAAO,CAAkB;IAEnC,YAAsB,MAAwB;QAC5C,IAAI,CAAC,OAAO,GAAG,MAAM;YACnB,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC;YACtD,CAAC,CAAC,IAAI,MAAM,CAAU,EAAE,IAAI,EAAE,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC,CAAC;IAC3D,CAAC;IAUD,KAAK,CAAC,YAAY,CAChB,QAAgB,EAChB,UAAkB,EAClB,OAAwB,EACxB,OAA8B;QAE9B,IAAI,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,EAAE,CAAC;YAC/B,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,wBAAwB,UAAU,EAAE,CAAC,CAAC;YACzD,IAAI,CAAC;gBACH,MAAM,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,UAAU,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;gBAC1D,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,sBAAsB,UAAU,EAAE,CAAC,CAAC;YACzD,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,sBAAsB,UAAU,EAAE,CAAC,CAAC;gBACtD,MAAM,KAAK,CAAC;YACd,CAAC;QACH,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,uBAAuB,UAAU,EAAE,CAAC,CAAC;QAC1D,CAAC;IACH,CAAC;CACF"}
@@ -0,0 +1,17 @@
1
+ import type { ILogObj } from 'tslog';
2
+ import { Logger } from 'tslog';
3
+ import type { IDeviceModelRepository } from '@citrineos/data';
4
+ import { IncomingMessage } from 'http';
5
+ import { AuthenticatorFilter } from './AuthenticatorFilter.js';
6
+ import type { AuthenticationOptions } from '@citrineos/base';
7
+ /**
8
+ * Filter used to authenticate incoming HTTP requests based on basic authorization header.
9
+ * It only applies when the security profile is set to 1 or 2.
10
+ */
11
+ export declare class BasicAuthenticationFilter extends AuthenticatorFilter {
12
+ private _deviceModelRepository;
13
+ constructor(deviceModelRepository: IDeviceModelRepository, logger?: Logger<ILogObj>);
14
+ protected shouldFilter(options: AuthenticationOptions): boolean;
15
+ protected filter(tenantId: number, identifier: string, request: IncomingMessage): Promise<void>;
16
+ private _isPasswordValid;
17
+ }