@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,51 @@
1
+ import { Logger } from 'tslog';
2
+ import { CryptoUtils } from '@citrineos/data';
3
+ import { IncomingMessage } from 'http';
4
+ import { extractBasicCredentials } from '../../util/RequestOperations.js';
5
+ import { AuthenticatorFilter } from './AuthenticatorFilter.js';
6
+ import { OCPP2_0_1 } from '@citrineos/base';
7
+ import { UpgradeAuthenticationError } from './errors/AuthenticationError.js';
8
+ /**
9
+ * Filter used to authenticate incoming HTTP requests based on basic authorization header.
10
+ * It only applies when the security profile is set to 1 or 2.
11
+ */
12
+ export class BasicAuthenticationFilter extends AuthenticatorFilter {
13
+ _deviceModelRepository;
14
+ constructor(deviceModelRepository, logger) {
15
+ super(logger);
16
+ this._deviceModelRepository = deviceModelRepository;
17
+ }
18
+ shouldFilter(options) {
19
+ return options.securityProfile === 1 || options.securityProfile === 2;
20
+ }
21
+ async filter(tenantId, identifier, request) {
22
+ const { username, password } = extractBasicCredentials(request);
23
+ if (!username || !password) {
24
+ throw new UpgradeAuthenticationError('Auth header missing or incorrectly formatted');
25
+ }
26
+ if (username !== identifier || !(await this._isPasswordValid(tenantId, username, password))) {
27
+ throw new UpgradeAuthenticationError(`Unauthorized ${identifier}`);
28
+ }
29
+ }
30
+ async _isPasswordValid(tenantId, username, password) {
31
+ return await this._deviceModelRepository
32
+ .readAllByQuerystring(tenantId, {
33
+ tenantId,
34
+ stationId: username,
35
+ component_name: 'SecurityCtrlr',
36
+ variable_name: 'BasicAuthPassword',
37
+ type: OCPP2_0_1.AttributeEnumType.Actual,
38
+ })
39
+ .then((r) => {
40
+ if (r && r[0]) {
41
+ const hashedPassword = r[0].value;
42
+ if (hashedPassword) {
43
+ return CryptoUtils.isPasswordMatch(hashedPassword, password);
44
+ }
45
+ }
46
+ this._logger.warn('Has no password', username);
47
+ return false;
48
+ });
49
+ }
50
+ }
51
+ //# sourceMappingURL=BasicAuthenticationFilter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BasicAuthenticationFilter.js","sourceRoot":"","sources":["../../../src/networkconnection/authenticator/BasicAuthenticationFilter.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AAE/B,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EAAE,eAAe,EAAE,MAAM,MAAM,CAAC;AACvC,OAAO,EAAE,uBAAuB,EAAE,MAAM,iCAAiC,CAAC;AAC1E,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAE/D,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,0BAA0B,EAAE,MAAM,iCAAiC,CAAC;AAE7E;;;GAGG;AACH,MAAM,OAAO,yBAA0B,SAAQ,mBAAmB;IACxD,sBAAsB,CAAyB;IAEvD,YAAY,qBAA6C,EAAE,MAAwB;QACjF,KAAK,CAAC,MAAM,CAAC,CAAC;QACd,IAAI,CAAC,sBAAsB,GAAG,qBAAqB,CAAC;IACtD,CAAC;IAES,YAAY,CAAC,OAA8B;QACnD,OAAO,OAAO,CAAC,eAAe,KAAK,CAAC,IAAI,OAAO,CAAC,eAAe,KAAK,CAAC,CAAC;IACxE,CAAC;IAES,KAAK,CAAC,MAAM,CACpB,QAAgB,EAChB,UAAkB,EAClB,OAAwB;QAExB,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,GAAG,uBAAuB,CAAC,OAAO,CAAC,CAAC;QAChE,IAAI,CAAC,QAAQ,IAAI,CAAC,QAAQ,EAAE,CAAC;YAC3B,MAAM,IAAI,0BAA0B,CAAC,8CAA8C,CAAC,CAAC;QACvF,CAAC;QAED,IAAI,QAAQ,KAAK,UAAU,IAAI,CAAC,CAAC,MAAM,IAAI,CAAC,gBAAgB,CAAC,QAAQ,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC,EAAE,CAAC;YAC5F,MAAM,IAAI,0BAA0B,CAAC,gBAAgB,UAAU,EAAE,CAAC,CAAC;QACrE,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,gBAAgB,CAAC,QAAgB,EAAE,QAAgB,EAAE,QAAgB;QACjF,OAAO,MAAM,IAAI,CAAC,sBAAsB;aACrC,oBAAoB,CAAC,QAAQ,EAAE;YAC9B,QAAQ;YACR,SAAS,EAAE,QAAQ;YACnB,cAAc,EAAE,eAAe;YAC/B,aAAa,EAAE,mBAAmB;YAClC,IAAI,EAAE,SAAS,CAAC,iBAAiB,CAAC,MAAM;SACzC,CAAC;aACD,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE;YACV,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;gBACd,MAAM,cAAc,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;gBAClC,IAAI,cAAc,EAAE,CAAC;oBACnB,OAAO,WAAW,CAAC,eAAe,CAAC,cAAc,EAAE,QAAQ,CAAC,CAAC;gBAC/D,CAAC;YACH,CAAC;YACD,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,iBAAiB,EAAE,QAAQ,CAAC,CAAC;YAC/C,OAAO,KAAK,CAAC;QACf,CAAC,CAAC,CAAC;IACP,CAAC;CACF"}
@@ -0,0 +1,14 @@
1
+ import type { AuthenticationOptions, ICache } from '@citrineos/base';
2
+ import type { ILogObj } from 'tslog';
3
+ import { Logger } from 'tslog';
4
+ import { IncomingMessage } from 'http';
5
+ import { AuthenticatorFilter } from './AuthenticatorFilter.js';
6
+ /**
7
+ * Filter used to prevent multiple simultaneous connections for the same charging station.
8
+ */
9
+ export declare class ConnectedStationFilter extends AuthenticatorFilter {
10
+ private _cache;
11
+ constructor(cache: ICache, logger?: Logger<ILogObj>);
12
+ protected shouldFilter(_options: AuthenticationOptions): boolean;
13
+ protected filter(tenantId: number, identifier: string, _request: IncomingMessage): Promise<void>;
14
+ }
@@ -0,0 +1,25 @@
1
+ import { CacheNamespace, notNull } from '@citrineos/base';
2
+ import { Logger } from 'tslog';
3
+ import { IncomingMessage } from 'http';
4
+ import { AuthenticatorFilter } from './AuthenticatorFilter.js';
5
+ import { UpgradeAuthenticationError } from './errors/AuthenticationError.js';
6
+ /**
7
+ * Filter used to prevent multiple simultaneous connections for the same charging station.
8
+ */
9
+ export class ConnectedStationFilter extends AuthenticatorFilter {
10
+ _cache;
11
+ constructor(cache, logger) {
12
+ super(logger);
13
+ this._cache = cache;
14
+ }
15
+ shouldFilter(_options) {
16
+ return true;
17
+ }
18
+ async filter(tenantId, identifier, _request) {
19
+ const isAlreadyConnected = notNull(await this._cache.get(identifier, CacheNamespace.Connections));
20
+ if (isAlreadyConnected) {
21
+ throw new UpgradeAuthenticationError(`New connection attempted for already connected identifier ${identifier}`);
22
+ }
23
+ }
24
+ }
25
+ //# sourceMappingURL=ConnectedStationFilter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ConnectedStationFilter.js","sourceRoot":"","sources":["../../../src/networkconnection/authenticator/ConnectedStationFilter.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAE1D,OAAO,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AAC/B,OAAO,EAAE,eAAe,EAAE,MAAM,MAAM,CAAC;AACvC,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAAE,0BAA0B,EAAE,MAAM,iCAAiC,CAAC;AAE7E;;GAEG;AACH,MAAM,OAAO,sBAAuB,SAAQ,mBAAmB;IACrD,MAAM,CAAS;IAEvB,YAAY,KAAa,EAAE,MAAwB;QACjD,KAAK,CAAC,MAAM,CAAC,CAAC;QACd,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;IACtB,CAAC;IAES,YAAY,CAAC,QAA+B;QACpD,OAAO,IAAI,CAAC;IACd,CAAC;IAES,KAAK,CAAC,MAAM,CACpB,QAAgB,EAChB,UAAkB,EAClB,QAAyB;QAEzB,MAAM,kBAAkB,GAAG,OAAO,CAChC,MAAM,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,UAAU,EAAE,cAAc,CAAC,WAAW,CAAC,CAC9D,CAAC;QACF,IAAI,kBAAkB,EAAE,CAAC;YACvB,MAAM,IAAI,0BAA0B,CAClC,6DAA6D,UAAU,EAAE,CAC1E,CAAC;QACJ,CAAC;IACH,CAAC;CACF"}
@@ -0,0 +1,16 @@
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 block connections when charging stations attempt to connect to disallowed security profiles
9
+ */
10
+ export declare class NetworkProfileFilter extends AuthenticatorFilter {
11
+ private _deviceModelRepository;
12
+ constructor(deviceModelRepository: IDeviceModelRepository, logger?: Logger<ILogObj>);
13
+ protected shouldFilter(_options: AuthenticationOptions): boolean;
14
+ protected filter(tenantId: number, identifier: string, request: IncomingMessage, options: AuthenticationOptions): Promise<void>;
15
+ private _isConfigurationSlotAllowed;
16
+ }
@@ -0,0 +1,84 @@
1
+ import { Logger } from 'tslog';
2
+ import { ChargingStationNetworkProfile, ServerNetworkProfile } from '@citrineos/data';
3
+ import { IncomingMessage } from 'http';
4
+ import { AuthenticatorFilter } from './AuthenticatorFilter.js';
5
+ import { OCPP2_0_1 } from '@citrineos/base';
6
+ import { UpgradeAuthenticationError } from './errors/AuthenticationError.js';
7
+ /**
8
+ * Filter used to block connections when charging stations attempt to connect to disallowed security profiles
9
+ */
10
+ export class NetworkProfileFilter extends AuthenticatorFilter {
11
+ _deviceModelRepository;
12
+ constructor(deviceModelRepository, logger) {
13
+ super(logger);
14
+ this._deviceModelRepository = deviceModelRepository;
15
+ }
16
+ shouldFilter(_options) {
17
+ return true;
18
+ }
19
+ async filter(tenantId, identifier, request, options) {
20
+ const isConfigurationSlotAllowed = await this._isConfigurationSlotAllowed(tenantId, identifier, options.securityProfile);
21
+ if (!isConfigurationSlotAllowed) {
22
+ throw new UpgradeAuthenticationError(`SecurityProfile not allowed ${options.securityProfile}`);
23
+ }
24
+ }
25
+ async _isConfigurationSlotAllowed(tenantId, identifier, securityProfile) {
26
+ const r = await this._deviceModelRepository.readAllByQuerystring(tenantId, {
27
+ tenantId,
28
+ stationId: identifier,
29
+ component_name: 'OCPPCommCtrlr',
30
+ variable_name: 'NetworkConfigurationPriority',
31
+ type: OCPP2_0_1.AttributeEnumType.Actual,
32
+ });
33
+ if (r && r[0]) {
34
+ const configurationSlotsString = r[0].value;
35
+ if (configurationSlotsString && configurationSlotsString.trim() !== '') {
36
+ // Split the string by commas to get an array of string numbers
37
+ const configurationSlotStringsArray = configurationSlotsString.split(',');
38
+ // Parse the array into numbers and filter out the rest
39
+ const configurationSlotsArray = configurationSlotStringsArray
40
+ .map((configurationSlotString) => parseInt(configurationSlotString, 10))
41
+ .filter((configurationSlotId) => {
42
+ if (isNaN(configurationSlotId)) {
43
+ this._logger.error('NetworkConfigurationPriority elements must be integers: ' +
44
+ configurationSlotsString);
45
+ return false;
46
+ }
47
+ else {
48
+ return true;
49
+ }
50
+ });
51
+ if (configurationSlotsArray.length == 0) {
52
+ this._logger.debug('No valid configuration slots to check: ' + configurationSlotsString);
53
+ return true;
54
+ }
55
+ else {
56
+ let securityProfileAllowed = false;
57
+ for (const configurationSlot of configurationSlotsArray) {
58
+ const chargingStationNetworkProfile = await ChargingStationNetworkProfile.findOne({
59
+ where: { stationId: identifier, configurationSlot: configurationSlot },
60
+ });
61
+ if (chargingStationNetworkProfile) {
62
+ const serverNetworkProfile = await ServerNetworkProfile.findByPk(chargingStationNetworkProfile.websocketServerConfigId);
63
+ if (serverNetworkProfile && securityProfile >= serverNetworkProfile.securityProfile) {
64
+ this._logger.debug('Security profile allowed');
65
+ securityProfileAllowed = true;
66
+ }
67
+ }
68
+ else {
69
+ this._logger.warn('Unknown configuration slot; skipping security profile network profile check.');
70
+ securityProfileAllowed = true;
71
+ }
72
+ }
73
+ if (!securityProfileAllowed) {
74
+ this._logger.warn(`Station ${identifier} unable to connect with security profile ${securityProfile}`);
75
+ }
76
+ return securityProfileAllowed;
77
+ }
78
+ }
79
+ }
80
+ this._logger.warn('Has no configuration slots configured');
81
+ return true;
82
+ }
83
+ }
84
+ //# sourceMappingURL=NetworkProfileFilter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NetworkProfileFilter.js","sourceRoot":"","sources":["../../../src/networkconnection/authenticator/NetworkProfileFilter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ import type { ILogObj } from 'tslog';
2
+ import { Logger } from 'tslog';
3
+ import type { ILocationRepository } 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 block connections from charging stations that are not recognized in the system.
9
+ * It only applies when unknown charging stations are not allowed.
10
+ */
11
+ export declare class UnknownStationFilter extends AuthenticatorFilter {
12
+ private _locationRepository;
13
+ constructor(locationRepository: ILocationRepository, logger?: Logger<ILogObj>);
14
+ protected shouldFilter(options: AuthenticationOptions): boolean;
15
+ protected filter(tenantId: number, identifier: string, _request: IncomingMessage): Promise<void>;
16
+ }
@@ -0,0 +1,25 @@
1
+ import { Logger } from 'tslog';
2
+ import { IncomingMessage } from 'http';
3
+ import { AuthenticatorFilter } from './AuthenticatorFilter.js';
4
+ import { UpgradeUnknownError } from './errors/UnknownError.js';
5
+ /**
6
+ * Filter used to block connections from charging stations that are not recognized in the system.
7
+ * It only applies when unknown charging stations are not allowed.
8
+ */
9
+ export class UnknownStationFilter extends AuthenticatorFilter {
10
+ _locationRepository;
11
+ constructor(locationRepository, logger) {
12
+ super(logger);
13
+ this._locationRepository = locationRepository;
14
+ }
15
+ shouldFilter(options) {
16
+ return !options.allowUnknownChargingStations;
17
+ }
18
+ async filter(tenantId, identifier, _request) {
19
+ const isStationKnown = await this._locationRepository.doesChargingStationExistByStationId(tenantId, identifier);
20
+ if (!isStationKnown) {
21
+ throw new UpgradeUnknownError(`Unknown identifier ${identifier}`);
22
+ }
23
+ }
24
+ }
25
+ //# sourceMappingURL=UnknownStationFilter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"UnknownStationFilter.js","sourceRoot":"","sources":["../../../src/networkconnection/authenticator/UnknownStationFilter.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AAE/B,OAAO,EAAE,eAAe,EAAE,MAAM,MAAM,CAAC;AACvC,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAE/D,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAE/D;;;GAGG;AACH,MAAM,OAAO,oBAAqB,SAAQ,mBAAmB;IACnD,mBAAmB,CAAsB;IAEjD,YAAY,kBAAuC,EAAE,MAAwB;QAC3E,KAAK,CAAC,MAAM,CAAC,CAAC;QACd,IAAI,CAAC,mBAAmB,GAAG,kBAAkB,CAAC;IAChD,CAAC;IAES,YAAY,CAAC,OAA8B;QACnD,OAAO,CAAC,OAAO,CAAC,4BAA4B,CAAC;IAC/C,CAAC;IAES,KAAK,CAAC,MAAM,CACpB,QAAgB,EAChB,UAAkB,EAClB,QAAyB;QAEzB,MAAM,cAAc,GAAG,MAAM,IAAI,CAAC,mBAAmB,CAAC,mCAAmC,CACvF,QAAQ,EACR,UAAU,CACX,CAAC;QACF,IAAI,CAAC,cAAc,EAAE,CAAC;YACpB,MAAM,IAAI,mBAAmB,CAAC,sBAAsB,UAAU,EAAE,CAAC,CAAC;QACpE,CAAC;IACH,CAAC;CACF"}
@@ -0,0 +1,6 @@
1
+ import { Duplex } from 'stream';
2
+ import type { IUpgradeError } from './IUpgradeError.js';
3
+ export declare class UpgradeAuthenticationError extends Error implements IUpgradeError {
4
+ constructor(message: string);
5
+ terminateConnection(socket: Duplex): boolean;
6
+ }
@@ -0,0 +1,25 @@
1
+ // SPDX-FileCopyrightText: 2025 Contributors to the CitrineOS Project
2
+ //
3
+ // SPDX-License-Identifier: Apache-2.0
4
+ import { Duplex } from 'stream';
5
+ export class UpgradeAuthenticationError extends Error {
6
+ constructor(message) {
7
+ super(message);
8
+ this.name = 'UpgradeAuthenticationError';
9
+ }
10
+ terminateConnection(socket) {
11
+ try {
12
+ socket.write('HTTP/1.1 401 Unauthorized\r\n');
13
+ socket.write('WWW-Authenticate: Basic realm="Access to the WebSocket", charset="UTF-8"\r\n');
14
+ socket.write('\r\n');
15
+ socket.end();
16
+ socket.destroy();
17
+ return true;
18
+ }
19
+ catch (error) {
20
+ this.message = error.message;
21
+ return false;
22
+ }
23
+ }
24
+ }
25
+ //# sourceMappingURL=AuthenticationError.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AuthenticationError.js","sourceRoot":"","sources":["../../../../src/networkconnection/authenticator/errors/AuthenticationError.ts"],"names":[],"mappings":"AAAA,qEAAqE;AACrE,EAAE;AACF,sCAAsC;AAEtC,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAGhC,MAAM,OAAO,0BAA2B,SAAQ,KAAK;IACnD,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,4BAA4B,CAAC;IAC3C,CAAC;IAED,mBAAmB,CAAC,MAAc;QAChC,IAAI,CAAC;YACH,MAAM,CAAC,KAAK,CAAC,+BAA+B,CAAC,CAAC;YAC9C,MAAM,CAAC,KAAK,CAAC,8EAA8E,CAAC,CAAC;YAC7F,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;YACrB,MAAM,CAAC,GAAG,EAAE,CAAC;YACb,MAAM,CAAC,OAAO,EAAE,CAAC;YACjB,OAAO,IAAI,CAAC;QACd,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,OAAO,GAAI,KAAe,CAAC,OAAO,CAAC;YACxC,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;CACF"}
@@ -0,0 +1,9 @@
1
+ import { Duplex } from 'stream';
2
+ export interface IUpgradeError {
3
+ /**
4
+ * Terminates the WebSocket connection by sending an error response and closing the socket.
5
+ * @param {Duplex} socket - The WebSocket duplex stream.
6
+ * @returns {boolean} True if the connection was terminated successfully, false otherwise.
7
+ */
8
+ terminateConnection(socket: Duplex): boolean;
9
+ }
@@ -0,0 +1,5 @@
1
+ // SPDX-FileCopyrightText: 2025 Contributors to the CitrineOS Project
2
+ //
3
+ // SPDX-License-Identifier: Apache-2.0
4
+ import { Duplex } from 'stream';
5
+ //# sourceMappingURL=IUpgradeError.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"IUpgradeError.js","sourceRoot":"","sources":["../../../../src/networkconnection/authenticator/errors/IUpgradeError.ts"],"names":[],"mappings":"AAAA,qEAAqE;AACrE,EAAE;AACF,sCAAsC;AAEtC,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC"}
@@ -0,0 +1,6 @@
1
+ import { Duplex } from 'stream';
2
+ import type { IUpgradeError } from './IUpgradeError.js';
3
+ export declare class UpgradeUnknownError extends Error implements IUpgradeError {
4
+ constructor(message: string);
5
+ terminateConnection(socket: Duplex): boolean;
6
+ }
@@ -0,0 +1,24 @@
1
+ // SPDX-FileCopyrightText: 2025 Contributors to the CitrineOS Project
2
+ //
3
+ // SPDX-License-Identifier: Apache-2.0
4
+ import { Duplex } from 'stream';
5
+ export class UpgradeUnknownError extends Error {
6
+ constructor(message) {
7
+ super(message);
8
+ this.name = 'UpgradeUnknownError';
9
+ }
10
+ terminateConnection(socket) {
11
+ try {
12
+ socket.write('HTTP/1.1 404 Not Found\r\n');
13
+ socket.write('\r\n');
14
+ socket.end();
15
+ socket.destroy();
16
+ return true;
17
+ }
18
+ catch (error) {
19
+ this.message = error.message;
20
+ return false;
21
+ }
22
+ }
23
+ }
24
+ //# sourceMappingURL=UnknownError.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"UnknownError.js","sourceRoot":"","sources":["../../../../src/networkconnection/authenticator/errors/UnknownError.ts"],"names":[],"mappings":"AAAA,qEAAqE;AACrE,EAAE;AACF,sCAAsC;AAEtC,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAGhC,MAAM,OAAO,mBAAoB,SAAQ,KAAK;IAC5C,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,qBAAqB,CAAC;IACpC,CAAC;IAED,mBAAmB,CAAC,MAAc;QAChC,IAAI,CAAC;YACH,MAAM,CAAC,KAAK,CAAC,4BAA4B,CAAC,CAAC;YAC3C,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;YACrB,MAAM,CAAC,GAAG,EAAE,CAAC;YACb,MAAM,CAAC,OAAO,EAAE,CAAC;YACjB,OAAO,IAAI,CAAC;QACd,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,OAAO,GAAI,KAAe,CAAC,OAAO,CAAC;YACxC,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;CACF"}
@@ -0,0 +1,5 @@
1
+ export { Authenticator } from './authenticator/Authenticator.js';
2
+ export { WebsocketNetworkConnection } from './WebsocketNetworkConnection.js';
3
+ export { BasicAuthenticationFilter } from './authenticator/BasicAuthenticationFilter.js';
4
+ export { ConnectedStationFilter } from './authenticator/ConnectedStationFilter.js';
5
+ export { UnknownStationFilter } from './authenticator/UnknownStationFilter.js';
@@ -0,0 +1,9 @@
1
+ // SPDX-FileCopyrightText: 2025 Contributors to the CitrineOS Project
2
+ //
3
+ // SPDX-License-Identifier: Apache-2.0
4
+ export { Authenticator } from './authenticator/Authenticator.js';
5
+ export { WebsocketNetworkConnection } from './WebsocketNetworkConnection.js';
6
+ export { BasicAuthenticationFilter } from './authenticator/BasicAuthenticationFilter.js';
7
+ export { ConnectedStationFilter } from './authenticator/ConnectedStationFilter.js';
8
+ export { UnknownStationFilter } from './authenticator/UnknownStationFilter.js';
9
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/networkconnection/index.ts"],"names":[],"mappings":"AAAA,qEAAqE;AACrE,EAAE;AACF,sCAAsC;AAEtC,OAAO,EAAE,aAAa,EAAE,MAAM,kCAAkC,CAAC;AACjE,OAAO,EAAE,0BAA0B,EAAE,MAAM,iCAAiC,CAAC;AAC7E,OAAO,EAAE,yBAAyB,EAAE,MAAM,8CAA8C,CAAC;AACzF,OAAO,EAAE,sBAAsB,EAAE,MAAM,2CAA2C,CAAC;AACnF,OAAO,EAAE,oBAAoB,EAAE,MAAM,yCAAyC,CAAC"}
@@ -0,0 +1,4 @@
1
+ export { RabbitMqReceiver } from './rabbit-mq/receiver.js';
2
+ export { RabbitMqSender } from './rabbit-mq/sender.js';
3
+ export { KafkaReceiver } from './kafka/receiver.js';
4
+ export { KafkaSender } from './kafka/sender.js';
@@ -0,0 +1,8 @@
1
+ // SPDX-FileCopyrightText: 2025 Contributors to the CitrineOS Project
2
+ //
3
+ // SPDX-License-Identifier: Apache-2.0
4
+ export { RabbitMqReceiver } from './rabbit-mq/receiver.js';
5
+ export { RabbitMqSender } from './rabbit-mq/sender.js';
6
+ export { KafkaReceiver } from './kafka/receiver.js';
7
+ export { KafkaSender } from './kafka/sender.js';
8
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/queue/index.ts"],"names":[],"mappings":"AAAA,qEAAqE;AACrE,EAAE;AACF,sCAAsC;AAEtC,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAEvD,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC"}
@@ -0,0 +1,35 @@
1
+ import type { CallAction, IMessageHandler, IModule, SystemConfig } from '@citrineos/base';
2
+ import { AbstractMessageHandler, CircuitBreaker } from '@citrineos/base';
3
+ import type { ILogObj } from 'tslog';
4
+ import { Logger } from 'tslog';
5
+ /**
6
+ * Implementation of a {@link IMessageHandler} using Kafka as the underlying transport.
7
+ */
8
+ export declare class KafkaReceiver extends AbstractMessageHandler implements IMessageHandler {
9
+ /**
10
+ * Fields
11
+ */
12
+ private _client;
13
+ private _topicName;
14
+ private _consumerMap;
15
+ private _circuitBreaker;
16
+ private _reconnectInterval?;
17
+ constructor(config: SystemConfig, logger?: Logger<ILogObj>, module?: IModule, circuitBreaker?: CircuitBreaker);
18
+ private _initAdmin;
19
+ subscribe(identifier: string, actions?: CallAction[], filter?: {
20
+ [k: string]: string;
21
+ }): Promise<boolean>;
22
+ unsubscribe(identifier: string): Promise<boolean>;
23
+ shutdown(): Promise<void>;
24
+ /**
25
+ * Private Methods
26
+ */
27
+ /**
28
+ * Underlying Kafka message handler.
29
+ *
30
+ * @param message The kafka message to process
31
+ */
32
+ private _onMessage;
33
+ private _onCircuitBreakerStateChange;
34
+ initConnection(): Promise<void>;
35
+ }
@@ -0,0 +1,179 @@
1
+ import { AbstractMessageHandler, CircuitBreaker, Message, OcppError, RetryMessageError, } from '@citrineos/base';
2
+ import { plainToInstance } from 'class-transformer';
3
+ import { Kafka } from 'kafkajs';
4
+ import { Logger } from 'tslog';
5
+ /**
6
+ * Implementation of a {@link IMessageHandler} using Kafka as the underlying transport.
7
+ */
8
+ export class KafkaReceiver extends AbstractMessageHandler {
9
+ /**
10
+ * Fields
11
+ */
12
+ _client;
13
+ _topicName;
14
+ _consumerMap;
15
+ _circuitBreaker;
16
+ _reconnectInterval;
17
+ constructor(config, logger, module, circuitBreaker) {
18
+ super(config, logger, module);
19
+ this._circuitBreaker = circuitBreaker ?? new CircuitBreaker();
20
+ this._circuitBreaker.onStateChange(this._onCircuitBreakerStateChange.bind(this));
21
+ this._consumerMap = new Map();
22
+ this._client = new Kafka({
23
+ brokers: this._config.util.messageBroker.kafka?.brokers || [],
24
+ ssl: true,
25
+ sasl: {
26
+ mechanism: 'plain',
27
+ username: this._config.util.messageBroker.kafka?.sasl.username || '',
28
+ password: this._config.util.messageBroker.kafka?.sasl.password || '',
29
+ },
30
+ });
31
+ this._topicName = `${this._config.util.messageBroker.kafka?.topicPrefix}-${this._config.util.messageBroker.kafka?.topicName}`;
32
+ this._initAdmin();
33
+ }
34
+ _initAdmin() {
35
+ const admin = this._client.admin();
36
+ admin
37
+ .connect()
38
+ .then(() => admin.listTopics())
39
+ .then((topics) => {
40
+ this._logger.debug('Topics:', topics);
41
+ if (!topics || topics.filter((topic) => topic === this._topicName).length === 0) {
42
+ this._client
43
+ .admin()
44
+ .createTopics({ topics: [{ topic: this._topicName }] })
45
+ .then(() => {
46
+ this._logger.debug(`Topic ${this._topicName} created.`);
47
+ this._circuitBreaker.triggerSuccess();
48
+ })
49
+ .catch((err) => {
50
+ this._logger.error('Error creating topic', err);
51
+ this._circuitBreaker.triggerFailure(err?.message);
52
+ });
53
+ }
54
+ else {
55
+ this._logger.debug(`Topic ${this._topicName} already exists.`);
56
+ this._circuitBreaker.triggerSuccess();
57
+ }
58
+ })
59
+ .then(() => admin.disconnect())
60
+ .catch((err) => {
61
+ this._logger.error(err);
62
+ this._circuitBreaker.triggerFailure(err?.message);
63
+ });
64
+ }
65
+ subscribe(identifier, actions, filter) {
66
+ if (this._circuitBreaker.state === 'CLOSED') {
67
+ this._logger.error('Circuit breaker is CLOSED. Cannot subscribe to Kafka topic.');
68
+ return Promise.resolve(false);
69
+ }
70
+ this._logger.debug(`Subscribing to ${this._topicName}...`, identifier, actions, filter);
71
+ const consumer = this._client.consumer({ groupId: 'test-group' });
72
+ return consumer
73
+ .connect()
74
+ .then(() => consumer.subscribe({ topic: this._topicName, fromBeginning: false }))
75
+ .then(() => consumer.run({
76
+ autoCommit: false,
77
+ eachMessage: (payload) => this._onMessage(payload, consumer),
78
+ }))
79
+ .then(() => this._consumerMap.set(identifier, consumer))
80
+ .then(() => true)
81
+ .catch((err) => {
82
+ this._logger.error(err);
83
+ this._circuitBreaker.triggerFailure(err?.message);
84
+ return false;
85
+ });
86
+ }
87
+ unsubscribe(identifier) {
88
+ const consumer = this._consumerMap.get(identifier);
89
+ if (!consumer) {
90
+ this._logger.error('Consumer not found', identifier);
91
+ return Promise.resolve(false);
92
+ }
93
+ return consumer
94
+ .disconnect()
95
+ .then(() => this._consumerMap.delete(identifier))
96
+ .catch((err) => {
97
+ this._logger.error(err);
98
+ return false;
99
+ });
100
+ }
101
+ async shutdown() {
102
+ for (const consumer of this._consumerMap.values()) {
103
+ await consumer.disconnect();
104
+ }
105
+ }
106
+ /**
107
+ * Private Methods
108
+ */
109
+ /**
110
+ * Underlying Kafka message handler.
111
+ *
112
+ * @param message The kafka message to process
113
+ */
114
+ async _onMessage({ topic, partition, message }, consumer) {
115
+ this._logger.debug(`Received message ${message.value?.toString()} on topic ${topic} partition ${partition}`);
116
+ try {
117
+ const messageValue = message.value;
118
+ if (messageValue) {
119
+ const parsed = plainToInstance((Message), messageValue.toString());
120
+ await this.handle(parsed, message.key?.toString());
121
+ }
122
+ }
123
+ catch (error) {
124
+ if (error instanceof RetryMessageError) {
125
+ this._logger.warn('Retrying message: ', error.message);
126
+ // Retryable error, usually ongoing call with station when trying to send new call
127
+ return;
128
+ }
129
+ else {
130
+ this._logger.error('Error while processing message:', error, message);
131
+ }
132
+ }
133
+ await consumer.commitOffsets([{ topic, partition, offset: message.offset }]);
134
+ }
135
+ _onCircuitBreakerStateChange(state, reason) {
136
+ this._logger.info(`[CircuitBreaker] State changed to ${state}${reason ? `: ${reason}` : ''}`);
137
+ switch (state) {
138
+ case 'FAILING':
139
+ this._logger.warn('Circuit breaker is FAILING. Kafka sender will not send messages until recovery. Reason:', reason);
140
+ break;
141
+ case 'CLOSED': {
142
+ this._logger.error('Circuit breaker is CLOSED. Shutting down Kafka receiver. Reason:', reason);
143
+ void this.shutdown();
144
+ if (this._reconnectInterval) {
145
+ clearInterval(this._reconnectInterval);
146
+ }
147
+ const delay = (this._config.maxReconnectDelay || 30) * 1000;
148
+ this._logger.warn(`Starting continuous reconnect attempts every ${delay / 1000} seconds while circuit breaker is CLOSED.`);
149
+ this._reconnectInterval = setInterval(() => {
150
+ this._logger.info('Attempting Kafka reconnect due to circuit breaker CLOSED...');
151
+ try {
152
+ this._initAdmin();
153
+ this._logger.info('Kafka reconnect attempt finished (success or already open).');
154
+ }
155
+ catch (err) {
156
+ this._logger.error('Kafka reconnect attempt failed.', err);
157
+ }
158
+ }, delay);
159
+ break;
160
+ }
161
+ case 'OPEN':
162
+ this._logger.info('Circuit breaker is OPEN. Will attempt to (re)initialize Kafka admin connection.');
163
+ if (this._reconnectInterval) {
164
+ this._logger.info('Clearing reconnect interval as circuit breaker is now OPEN.');
165
+ clearInterval(this._reconnectInterval);
166
+ this._reconnectInterval = undefined;
167
+ }
168
+ this._initAdmin();
169
+ break;
170
+ default:
171
+ this._logger.warn('Unknown circuit breaker state:', state);
172
+ break;
173
+ }
174
+ }
175
+ initConnection() {
176
+ return Promise.resolve(undefined);
177
+ }
178
+ }
179
+ //# sourceMappingURL=receiver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"receiver.js","sourceRoot":"","sources":["../../../src/queue/kafka/receiver.ts"],"names":[],"mappings":"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"}