@brightchain/brightchain-api-lib 0.24.1 → 0.26.0

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 (244) hide show
  1. package/package.json +4 -3
  2. package/src/lib/application.d.ts +3 -14
  3. package/src/lib/application.d.ts.map +1 -1
  4. package/src/lib/application.js +121 -44
  5. package/src/lib/application.js.map +1 -1
  6. package/src/lib/auth/aclDocumentStore.d.ts +90 -0
  7. package/src/lib/auth/aclDocumentStore.d.ts.map +1 -0
  8. package/src/lib/auth/aclDocumentStore.js +155 -0
  9. package/src/lib/auth/aclDocumentStore.js.map +1 -0
  10. package/src/lib/auth/index.d.ts +4 -0
  11. package/src/lib/auth/index.d.ts.map +1 -1
  12. package/src/lib/auth/index.js +4 -0
  13. package/src/lib/auth/index.js.map +1 -1
  14. package/src/lib/auth/writeAclApiRouter.d.ts +32 -0
  15. package/src/lib/auth/writeAclApiRouter.d.ts.map +1 -0
  16. package/src/lib/auth/writeAclApiRouter.js +348 -0
  17. package/src/lib/auth/writeAclApiRouter.js.map +1 -0
  18. package/src/lib/auth/writeAclAuditLogger.d.ts +94 -0
  19. package/src/lib/auth/writeAclAuditLogger.d.ts.map +1 -0
  20. package/src/lib/auth/writeAclAuditLogger.js +143 -0
  21. package/src/lib/auth/writeAclAuditLogger.js.map +1 -0
  22. package/src/lib/auth/writeProofMiddleware.d.ts +39 -0
  23. package/src/lib/auth/writeProofMiddleware.d.ts.map +1 -0
  24. package/src/lib/auth/writeProofMiddleware.js +56 -0
  25. package/src/lib/auth/writeProofMiddleware.js.map +1 -0
  26. package/src/lib/availability/aclDocumentSyncHandler.d.ts +39 -0
  27. package/src/lib/availability/aclDocumentSyncHandler.d.ts.map +1 -0
  28. package/src/lib/availability/aclDocumentSyncHandler.js +81 -0
  29. package/src/lib/availability/aclDocumentSyncHandler.js.map +1 -0
  30. package/src/lib/availability/gossipService.d.ts +4 -1
  31. package/src/lib/availability/gossipService.d.ts.map +1 -1
  32. package/src/lib/availability/gossipService.js +15 -1
  33. package/src/lib/availability/gossipService.js.map +1 -1
  34. package/src/lib/availability/headUpdateSyncHandler.d.ts +32 -0
  35. package/src/lib/availability/headUpdateSyncHandler.d.ts.map +1 -0
  36. package/src/lib/availability/headUpdateSyncHandler.js +78 -0
  37. package/src/lib/availability/headUpdateSyncHandler.js.map +1 -0
  38. package/src/lib/availability/index.d.ts +2 -0
  39. package/src/lib/availability/index.d.ts.map +1 -1
  40. package/src/lib/availability/index.js +2 -0
  41. package/src/lib/availability/index.js.map +1 -1
  42. package/src/lib/constants.d.ts.map +1 -1
  43. package/src/lib/constants.js +2 -0
  44. package/src/lib/constants.js.map +1 -1
  45. package/src/lib/controllers/api/brighthub/connectionController.d.ts +6 -0
  46. package/src/lib/controllers/api/brighthub/connectionController.d.ts.map +1 -1
  47. package/src/lib/controllers/api/brighthub/connectionController.js +158 -11
  48. package/src/lib/controllers/api/brighthub/connectionController.js.map +1 -1
  49. package/src/lib/controllers/api/brighthub/messagingController.d.ts +6 -0
  50. package/src/lib/controllers/api/brighthub/messagingController.d.ts.map +1 -1
  51. package/src/lib/controllers/api/brighthub/messagingController.js +190 -58
  52. package/src/lib/controllers/api/brighthub/messagingController.js.map +1 -1
  53. package/src/lib/controllers/api/brighthub/postController.d.ts +12 -3
  54. package/src/lib/controllers/api/brighthub/postController.d.ts.map +1 -1
  55. package/src/lib/controllers/api/brighthub/postController.js +60 -0
  56. package/src/lib/controllers/api/brighthub/postController.js.map +1 -1
  57. package/src/lib/controllers/api/brighthub/timelineController.d.ts +19 -0
  58. package/src/lib/controllers/api/brighthub/timelineController.d.ts.map +1 -1
  59. package/src/lib/controllers/api/brighthub/timelineController.js +133 -0
  60. package/src/lib/controllers/api/brighthub/timelineController.js.map +1 -1
  61. package/src/lib/controllers/api/emails.d.ts +4 -1
  62. package/src/lib/controllers/api/emails.d.ts.map +1 -1
  63. package/src/lib/controllers/api/emails.js +28 -1
  64. package/src/lib/controllers/api/emails.js.map +1 -1
  65. package/src/lib/controllers/api/user.d.ts.map +1 -1
  66. package/src/lib/controllers/api/user.js +10 -0
  67. package/src/lib/controllers/api/user.js.map +1 -1
  68. package/src/lib/databaseInit.d.ts +7 -11
  69. package/src/lib/databaseInit.d.ts.map +1 -1
  70. package/src/lib/databaseInit.js +41 -97
  71. package/src/lib/databaseInit.js.map +1 -1
  72. package/src/lib/datastore/block-document-store-factory.d.ts +3 -0
  73. package/src/lib/datastore/block-document-store-factory.d.ts.map +1 -1
  74. package/src/lib/datastore/block-document-store-factory.js +15 -18
  75. package/src/lib/datastore/block-document-store-factory.js.map +1 -1
  76. package/src/lib/datastore/block-document-store.d.ts +2 -191
  77. package/src/lib/datastore/block-document-store.d.ts.map +1 -1
  78. package/src/lib/datastore/block-document-store.js +4 -628
  79. package/src/lib/datastore/block-document-store.js.map +1 -1
  80. package/src/lib/datastore/document-store.d.ts +1 -62
  81. package/src/lib/datastore/document-store.d.ts.map +1 -1
  82. package/src/lib/datastore/memory-document-store.d.ts +1 -8
  83. package/src/lib/datastore/memory-document-store.d.ts.map +1 -1
  84. package/src/lib/datastore/memory-document-store.js +3 -214
  85. package/src/lib/datastore/memory-document-store.js.map +1 -1
  86. package/src/lib/environment.d.ts +3 -20
  87. package/src/lib/environment.d.ts.map +1 -1
  88. package/src/lib/environment.js +2 -45
  89. package/src/lib/environment.js.map +1 -1
  90. package/src/lib/factories/blockStoreFactory.d.ts.map +1 -1
  91. package/src/lib/factories/blockStoreFactory.js +4 -1
  92. package/src/lib/factories/blockStoreFactory.js.map +1 -1
  93. package/src/lib/interfaces/environment.d.ts +23 -2
  94. package/src/lib/interfaces/environment.d.ts.map +1 -1
  95. package/src/lib/interfaces/responses/brighthub/api-post-response.d.ts +8 -1
  96. package/src/lib/interfaces/responses/brighthub/api-post-response.d.ts.map +1 -1
  97. package/src/lib/middleware/index.d.ts +1 -1
  98. package/src/lib/middleware/index.d.ts.map +1 -1
  99. package/src/lib/middleware/index.js +3 -2
  100. package/src/lib/middleware/index.js.map +1 -1
  101. package/src/lib/middleware/validateBody.d.ts +1 -12
  102. package/src/lib/middleware/validateBody.d.ts.map +1 -1
  103. package/src/lib/middleware/validateBody.js +4 -32
  104. package/src/lib/middleware/validateBody.js.map +1 -1
  105. package/src/lib/middlewares.d.ts.map +1 -1
  106. package/src/lib/middlewares.js +7 -1
  107. package/src/lib/middlewares.js.map +1 -1
  108. package/src/lib/plugins/brightchain-database-plugin.d.ts +27 -79
  109. package/src/lib/plugins/brightchain-database-plugin.d.ts.map +1 -1
  110. package/src/lib/plugins/brightchain-database-plugin.js +27 -97
  111. package/src/lib/plugins/brightchain-database-plugin.js.map +1 -1
  112. package/src/lib/routers/api.d.ts +18 -1
  113. package/src/lib/routers/api.d.ts.map +1 -1
  114. package/src/lib/routers/api.js +24 -1
  115. package/src/lib/routers/api.js.map +1 -1
  116. package/src/lib/routers/app.d.ts.map +1 -1
  117. package/src/lib/routers/app.js +5 -2
  118. package/src/lib/routers/app.js.map +1 -1
  119. package/src/lib/services/auth.d.ts.map +1 -1
  120. package/src/lib/services/auth.js +37 -3
  121. package/src/lib/services/auth.js.map +1 -1
  122. package/src/lib/services/blockStore.d.ts +8 -1
  123. package/src/lib/services/blockStore.d.ts.map +1 -1
  124. package/src/lib/services/blockStore.js +19 -7
  125. package/src/lib/services/blockStore.js.map +1 -1
  126. package/src/lib/services/brightChainBackupCodeService.d.ts +42 -39
  127. package/src/lib/services/brightChainBackupCodeService.d.ts.map +1 -1
  128. package/src/lib/services/brightChainBackupCodeService.js +86 -61
  129. package/src/lib/services/brightChainBackupCodeService.js.map +1 -1
  130. package/src/lib/services/brighthub/collectionAdapter.d.ts +81 -0
  131. package/src/lib/services/brighthub/collectionAdapter.d.ts.map +1 -0
  132. package/src/lib/services/brighthub/collectionAdapter.js +127 -0
  133. package/src/lib/services/brighthub/collectionAdapter.js.map +1 -0
  134. package/src/lib/services/brighthub/connectionService.d.ts.map +1 -1
  135. package/src/lib/services/brighthub/connectionService.js +3 -0
  136. package/src/lib/services/brighthub/connectionService.js.map +1 -1
  137. package/src/lib/services/brighthub/messagingService.d.ts +4 -0
  138. package/src/lib/services/brighthub/messagingService.d.ts.map +1 -1
  139. package/src/lib/services/brighthub/messagingService.js +25 -4
  140. package/src/lib/services/brighthub/messagingService.js.map +1 -1
  141. package/src/lib/services/brighthub/notificationService.d.ts.map +1 -1
  142. package/src/lib/services/brighthub/notificationService.js +35 -20
  143. package/src/lib/services/brighthub/notificationService.js.map +1 -1
  144. package/src/lib/services/brighthub/postService.d.ts +7 -1
  145. package/src/lib/services/brighthub/postService.d.ts.map +1 -1
  146. package/src/lib/services/brighthub/postService.js +22 -1
  147. package/src/lib/services/brighthub/postService.js.map +1 -1
  148. package/src/lib/services/brighthub/userProfileService.d.ts +19 -1
  149. package/src/lib/services/brighthub/userProfileService.d.ts.map +1 -1
  150. package/src/lib/services/brighthub/userProfileService.js +74 -0
  151. package/src/lib/services/brighthub/userProfileService.js.map +1 -1
  152. package/src/lib/services/emailGateway/antiSpamFilter.d.ts +229 -0
  153. package/src/lib/services/emailGateway/antiSpamFilter.d.ts.map +1 -0
  154. package/src/lib/services/emailGateway/antiSpamFilter.js +325 -0
  155. package/src/lib/services/emailGateway/antiSpamFilter.js.map +1 -0
  156. package/src/lib/services/emailGateway/bounceProcessor.d.ts +171 -0
  157. package/src/lib/services/emailGateway/bounceProcessor.d.ts.map +1 -0
  158. package/src/lib/services/emailGateway/bounceProcessor.js +378 -0
  159. package/src/lib/services/emailGateway/bounceProcessor.js.map +1 -0
  160. package/src/lib/services/emailGateway/emailAuthVerifier.d.ts +99 -0
  161. package/src/lib/services/emailGateway/emailAuthVerifier.d.ts.map +1 -0
  162. package/src/lib/services/emailGateway/emailAuthVerifier.js +202 -0
  163. package/src/lib/services/emailGateway/emailAuthVerifier.js.map +1 -0
  164. package/src/lib/services/emailGateway/emailGatewayConfig.d.ts +73 -0
  165. package/src/lib/services/emailGateway/emailGatewayConfig.d.ts.map +1 -0
  166. package/src/lib/services/emailGateway/emailGatewayConfig.js +107 -0
  167. package/src/lib/services/emailGateway/emailGatewayConfig.js.map +1 -0
  168. package/src/lib/services/emailGateway/emailGatewayService.d.ts +152 -0
  169. package/src/lib/services/emailGateway/emailGatewayService.d.ts.map +1 -0
  170. package/src/lib/services/emailGateway/emailGatewayService.js +201 -0
  171. package/src/lib/services/emailGateway/emailGatewayService.js.map +1 -0
  172. package/src/lib/services/emailGateway/gatewayObservability.d.ts +123 -0
  173. package/src/lib/services/emailGateway/gatewayObservability.d.ts.map +1 -0
  174. package/src/lib/services/emailGateway/gatewayObservability.js +186 -0
  175. package/src/lib/services/emailGateway/gatewayObservability.js.map +1 -0
  176. package/src/lib/services/emailGateway/inboundProcessor.d.ts +113 -0
  177. package/src/lib/services/emailGateway/inboundProcessor.d.ts.map +1 -0
  178. package/src/lib/services/emailGateway/inboundProcessor.js +298 -0
  179. package/src/lib/services/emailGateway/inboundProcessor.js.map +1 -0
  180. package/src/lib/services/emailGateway/index.d.ts +23 -0
  181. package/src/lib/services/emailGateway/index.d.ts.map +1 -0
  182. package/src/lib/services/emailGateway/index.js +26 -0
  183. package/src/lib/services/emailGateway/index.js.map +1 -0
  184. package/src/lib/services/emailGateway/outboundDeliveryWorker.d.ts +111 -0
  185. package/src/lib/services/emailGateway/outboundDeliveryWorker.d.ts.map +1 -0
  186. package/src/lib/services/emailGateway/outboundDeliveryWorker.js +97 -0
  187. package/src/lib/services/emailGateway/outboundDeliveryWorker.js.map +1 -0
  188. package/src/lib/services/emailGateway/outboundQueue.d.ts +135 -0
  189. package/src/lib/services/emailGateway/outboundQueue.d.ts.map +1 -0
  190. package/src/lib/services/emailGateway/outboundQueue.js +227 -0
  191. package/src/lib/services/emailGateway/outboundQueue.js.map +1 -0
  192. package/src/lib/services/emailGateway/outboundQueueStore.d.ts +110 -0
  193. package/src/lib/services/emailGateway/outboundQueueStore.d.ts.map +1 -0
  194. package/src/lib/services/emailGateway/outboundQueueStore.js +131 -0
  195. package/src/lib/services/emailGateway/outboundQueueStore.js.map +1 -0
  196. package/src/lib/services/emailGateway/recipientLookupService.d.ts +135 -0
  197. package/src/lib/services/emailGateway/recipientLookupService.d.ts.map +1 -0
  198. package/src/lib/services/emailGateway/recipientLookupService.js +294 -0
  199. package/src/lib/services/emailGateway/recipientLookupService.js.map +1 -0
  200. package/src/lib/services/emailGateway/retryBackoff.d.ts +79 -0
  201. package/src/lib/services/emailGateway/retryBackoff.d.ts.map +1 -0
  202. package/src/lib/services/emailGateway/retryBackoff.js +77 -0
  203. package/src/lib/services/emailGateway/retryBackoff.js.map +1 -0
  204. package/src/lib/services/eventNotificationSystem.d.ts.map +1 -1
  205. package/src/lib/services/eventNotificationSystem.js.map +1 -1
  206. package/src/lib/services/index.d.ts +2 -1
  207. package/src/lib/services/index.d.ts.map +1 -1
  208. package/src/lib/services/index.js +2 -1
  209. package/src/lib/services/index.js.map +1 -1
  210. package/src/lib/services/quorumDatabaseAdapter.d.ts +7 -1
  211. package/src/lib/services/quorumDatabaseAdapter.d.ts.map +1 -1
  212. package/src/lib/services/quorumDatabaseAdapter.js +83 -0
  213. package/src/lib/services/quorumDatabaseAdapter.js.map +1 -1
  214. package/src/lib/services/sessionAdapter.d.ts +2 -61
  215. package/src/lib/services/sessionAdapter.d.ts.map +1 -1
  216. package/src/lib/services/sessionAdapter.js +2 -102
  217. package/src/lib/services/sessionAdapter.js.map +1 -1
  218. package/src/lib/shared-types.d.ts +7 -15
  219. package/src/lib/shared-types.d.ts.map +1 -1
  220. package/src/lib/stores/availabilityAwareBlockStore.d.ts +4 -3
  221. package/src/lib/stores/availabilityAwareBlockStore.d.ts.map +1 -1
  222. package/src/lib/stores/availabilityAwareBlockStore.js +5 -2
  223. package/src/lib/stores/availabilityAwareBlockStore.js.map +1 -1
  224. package/src/lib/stores/cloudBlockStoreBase.d.ts +2 -1
  225. package/src/lib/stores/cloudBlockStoreBase.d.ts.map +1 -1
  226. package/src/lib/stores/cloudBlockStoreBase.js +34 -13
  227. package/src/lib/stores/cloudBlockStoreBase.js.map +1 -1
  228. package/src/lib/stores/diskBlockAsyncStore.d.ts +21 -1
  229. package/src/lib/stores/diskBlockAsyncStore.d.ts.map +1 -1
  230. package/src/lib/stores/diskBlockAsyncStore.js +48 -17
  231. package/src/lib/stores/diskBlockAsyncStore.js.map +1 -1
  232. package/src/lib/stores/diskBlockStore.d.ts +10 -2
  233. package/src/lib/stores/diskBlockStore.d.ts.map +1 -1
  234. package/src/lib/stores/diskBlockStore.js +43 -19
  235. package/src/lib/stores/diskBlockStore.js.map +1 -1
  236. package/src/lib/types/backend-id.d.ts +1 -2
  237. package/src/lib/types/backend-id.d.ts.map +1 -1
  238. package/src/lib/utils/emailValidation.d.ts.map +1 -1
  239. package/src/lib/utils/emailValidation.js +2 -1
  240. package/src/lib/utils/emailValidation.js.map +1 -1
  241. package/src/lib/validation/userValidation.d.ts +2 -43
  242. package/src/lib/validation/userValidation.d.ts.map +1 -1
  243. package/src/lib/validation/userValidation.js +6 -144
  244. package/src/lib/validation/userValidation.js.map +1 -1
@@ -0,0 +1,325 @@
1
+ "use strict";
2
+ /**
3
+ * AntiSpamFilter — milter integration adapter for SpamAssassin/Rspamd
4
+ * score classification of inbound email messages.
5
+ *
6
+ * The filter wraps a configurable spam engine client (SpamAssassin via
7
+ * spamc protocol or Rspamd via HTTP API) and classifies messages as
8
+ * ham, probable-spam, or definite-spam based on configurable score
9
+ * thresholds from `ISpamThresholds`.
10
+ *
11
+ * Integration with Postfix is via the milter protocol (RFC 6008):
12
+ * - Definite-spam → signal rejection (SMFIS_REJECT, 550)
13
+ * - Probable-spam → accept and tag metadata with spam flag and score
14
+ * - Ham → accept without modification
15
+ *
16
+ * @see Requirements 7.1, 7.2, 7.3, 7.4, 7.5
17
+ * @module antiSpamFilter
18
+ */
19
+ Object.defineProperty(exports, "__esModule", { value: true });
20
+ exports.AntiSpamFilter = exports.RspamdClient = exports.SpamAssassinClient = void 0;
21
+ const tslib_1 = require("tslib");
22
+ const http = tslib_1.__importStar(require("http"));
23
+ const net = tslib_1.__importStar(require("net"));
24
+ const brightchain_lib_1 = require("@brightchain/brightchain-lib");
25
+ // ─── SpamAssassin Client ────────────────────────────────────────────────────
26
+ /**
27
+ * SpamAssassin engine client — communicates with spamd via the spamc
28
+ * TCP protocol (default port 783).
29
+ *
30
+ * Protocol overview:
31
+ * 1. Connect to spamd TCP socket
32
+ * 2. Send `SYMBOLS SPAMC/1.5\r\nContent-length: <len>\r\n\r\n<message>`
33
+ * 3. Parse response for `Spam: True/False ; <score> / <threshold>` header
34
+ *
35
+ * @see Requirement 7.1
36
+ */
37
+ class SpamAssassinClient {
38
+ host;
39
+ port;
40
+ timeoutMs;
41
+ constructor(host = 'localhost', port = 783, timeoutMs = 30_000) {
42
+ this.host = host;
43
+ this.port = port;
44
+ this.timeoutMs = timeoutMs;
45
+ }
46
+ async scan(rawMessage) {
47
+ return new Promise((resolve, reject) => {
48
+ const socket = net.createConnection({ host: this.host, port: this.port }, () => {
49
+ const request = `SYMBOLS SPAMC/1.5\r\n` +
50
+ `Content-length: ${rawMessage.length}\r\n` +
51
+ `\r\n`;
52
+ socket.write(request);
53
+ socket.write(rawMessage);
54
+ });
55
+ socket.setTimeout(this.timeoutMs);
56
+ const chunks = [];
57
+ socket.on('data', (chunk) => {
58
+ chunks.push(chunk);
59
+ });
60
+ socket.on('end', () => {
61
+ const response = Buffer.concat(chunks).toString('utf-8');
62
+ resolve(SpamAssassinClient.parseResponse(response));
63
+ });
64
+ socket.on('timeout', () => {
65
+ socket.destroy();
66
+ reject(new Error('SpamAssassin spamd connection timed out'));
67
+ });
68
+ socket.on('error', (err) => {
69
+ reject(new Error(`SpamAssassin spamd connection error: ${err.message}`));
70
+ });
71
+ });
72
+ }
73
+ /**
74
+ * Parse the spamd response to extract score and spam determination.
75
+ *
76
+ * Expected header line format:
77
+ * `Spam: True ; 15.3 / 5.0`
78
+ * `Spam: False ; 1.2 / 5.0`
79
+ */
80
+ static parseResponse(response) {
81
+ const spamMatch = response.match(/Spam:\s*(True|False|Yes|No)\s*;\s*([\d.]+)\s*\/\s*([\d.]+)/i);
82
+ if (!spamMatch) {
83
+ return {
84
+ score: 0,
85
+ isSpam: false,
86
+ details: 'Unable to parse spamd response',
87
+ };
88
+ }
89
+ const isSpam = spamMatch[1].toLowerCase() === 'true' ||
90
+ spamMatch[1].toLowerCase() === 'yes';
91
+ const score = parseFloat(spamMatch[2]);
92
+ // Extract rule matches from the body (lines after headers)
93
+ const bodyStart = response.indexOf('\r\n\r\n');
94
+ const details = bodyStart >= 0 ? response.substring(bodyStart + 4).trim() : undefined;
95
+ return { score, isSpam, details: details || undefined };
96
+ }
97
+ }
98
+ exports.SpamAssassinClient = SpamAssassinClient;
99
+ // ─── Rspamd Client ──────────────────────────────────────────────────────────
100
+ /**
101
+ * Rspamd engine client — communicates with rspamd via its HTTP API
102
+ * (default port 11333).
103
+ *
104
+ * Protocol overview:
105
+ * 1. POST raw message to `http://<host>:<port>/checkv2`
106
+ * 2. Parse JSON response for `score`, `is_spam`/`action`, and `symbols`
107
+ *
108
+ * @see Requirement 7.1
109
+ */
110
+ class RspamdClient {
111
+ host;
112
+ port;
113
+ timeoutMs;
114
+ constructor(host = 'localhost', port = 11333, timeoutMs = 30_000) {
115
+ this.host = host;
116
+ this.port = port;
117
+ this.timeoutMs = timeoutMs;
118
+ }
119
+ async scan(rawMessage) {
120
+ return new Promise((resolve, reject) => {
121
+ const options = {
122
+ hostname: this.host,
123
+ port: this.port,
124
+ path: '/checkv2',
125
+ method: 'POST',
126
+ headers: {
127
+ 'Content-Length': rawMessage.length,
128
+ },
129
+ timeout: this.timeoutMs,
130
+ };
131
+ const req = http.request(options, (res) => {
132
+ const chunks = [];
133
+ res.on('data', (chunk) => {
134
+ chunks.push(chunk);
135
+ });
136
+ res.on('end', () => {
137
+ const body = Buffer.concat(chunks).toString('utf-8');
138
+ try {
139
+ resolve(RspamdClient.parseResponse(body));
140
+ }
141
+ catch (err) {
142
+ reject(new Error(`Rspamd response parse error: ${err instanceof Error ? err.message : String(err)}`));
143
+ }
144
+ });
145
+ });
146
+ req.on('timeout', () => {
147
+ req.destroy();
148
+ reject(new Error('Rspamd HTTP connection timed out'));
149
+ });
150
+ req.on('error', (err) => {
151
+ reject(new Error(`Rspamd HTTP connection error: ${err.message}`));
152
+ });
153
+ req.write(rawMessage);
154
+ req.end();
155
+ });
156
+ }
157
+ /**
158
+ * Parse the Rspamd JSON response.
159
+ *
160
+ * Expected JSON structure:
161
+ * ```json
162
+ * {
163
+ * "score": 15.3,
164
+ * "required_score": 15.0,
165
+ * "action": "reject" | "add header" | "no action" | ...,
166
+ * "symbols": { ... }
167
+ * }
168
+ * ```
169
+ */
170
+ static parseResponse(body) {
171
+ let parsed;
172
+ try {
173
+ parsed = JSON.parse(body);
174
+ }
175
+ catch {
176
+ return {
177
+ score: 0,
178
+ isSpam: false,
179
+ details: 'Unable to parse Rspamd JSON response',
180
+ };
181
+ }
182
+ const score = typeof parsed['score'] === 'number' ? parsed['score'] : 0;
183
+ const action = typeof parsed['action'] === 'string' ? parsed['action'] : '';
184
+ // Rspamd actions: "reject", "rewrite subject", "add header",
185
+ // "greylist", "no action", "soft reject"
186
+ const isSpam = action === 'reject' || action === 'add header';
187
+ // Summarize matched symbols if available
188
+ let details;
189
+ if (parsed['symbols'] &&
190
+ typeof parsed['symbols'] === 'object' &&
191
+ parsed['symbols'] !== null) {
192
+ const symbolNames = Object.keys(parsed['symbols']);
193
+ if (symbolNames.length > 0) {
194
+ details = symbolNames.join(', ');
195
+ }
196
+ }
197
+ return { score, isSpam, details };
198
+ }
199
+ }
200
+ exports.RspamdClient = RspamdClient;
201
+ // ─── Anti-Spam Filter Implementation ────────────────────────────────────────
202
+ /**
203
+ * Milter integration adapter for SpamAssassin/Rspamd score classification.
204
+ *
205
+ * Wraps a configurable spam engine client and classifies messages based
206
+ * on `ISpamThresholds`:
207
+ * - score < probableSpamScore → Ham (accept)
208
+ * - probableSpamScore ≤ score < definiteSpamScore → ProbableSpam (tag metadata)
209
+ * - score ≥ definiteSpamScore → DefiniteSpam (reject 550)
210
+ *
211
+ * @see Requirements 7.1, 7.2, 7.3, 7.4, 7.5
212
+ */
213
+ class AntiSpamFilter {
214
+ engineClient;
215
+ thresholds;
216
+ /**
217
+ * Create an AntiSpamFilter with the specified engine and thresholds.
218
+ *
219
+ * @param engine - Which spam engine to use: `'spamassassin'` or `'rspamd'`
220
+ * @param thresholds - Score thresholds for classification
221
+ * @param engineClient - Optional pre-configured engine client (for testing / DI)
222
+ * @param engineHost - Host for the spam engine (default: localhost)
223
+ * @param enginePort - Port for the spam engine (default: engine-specific)
224
+ */
225
+ constructor(engine, thresholds, engineClient, engineHost, enginePort) {
226
+ this.thresholds = thresholds;
227
+ if (engineClient) {
228
+ this.engineClient = engineClient;
229
+ }
230
+ else if (engine === 'rspamd') {
231
+ this.engineClient = new RspamdClient(engineHost ?? 'localhost', enginePort ?? 11333);
232
+ }
233
+ else {
234
+ this.engineClient = new SpamAssassinClient(engineHost ?? 'localhost', enginePort ?? 783);
235
+ }
236
+ }
237
+ /**
238
+ * Classify a spam score against the configured thresholds.
239
+ *
240
+ * @param score - Numeric spam score from the engine
241
+ * @returns The spam classification
242
+ *
243
+ * @see Requirement 7.2
244
+ */
245
+ classify(score) {
246
+ if (score >= this.thresholds.definiteSpamScore) {
247
+ return brightchain_lib_1.SpamClassification.DefiniteSpam;
248
+ }
249
+ if (score >= this.thresholds.probableSpamScore) {
250
+ return brightchain_lib_1.SpamClassification.ProbableSpam;
251
+ }
252
+ return brightchain_lib_1.SpamClassification.Ham;
253
+ }
254
+ /**
255
+ * Scan a raw email message and return the spam classification result.
256
+ *
257
+ * Delegates to the configured spam engine client, then classifies
258
+ * the returned score against the configured thresholds.
259
+ *
260
+ * @param rawMessage - The raw RFC 5322 message bytes
261
+ * @returns Scan result with score, classification, and optional details
262
+ *
263
+ * @see Requirements 7.1, 7.2
264
+ */
265
+ async scan(rawMessage) {
266
+ const engineResult = await this.engineClient.scan(rawMessage);
267
+ const classification = this.classify(engineResult.score);
268
+ return {
269
+ score: engineResult.score,
270
+ classification,
271
+ details: engineResult.details,
272
+ };
273
+ }
274
+ /**
275
+ * Scan a message and return the milter protocol response for Postfix.
276
+ *
277
+ * Maps classification to milter actions:
278
+ * - DefiniteSpam → reject (SMFIS_REJECT, 550)
279
+ * - ProbableSpam → continue with X-Spam-Flag / X-Spam-Score headers
280
+ * - Ham → accept
281
+ *
282
+ * @param rawMessage - The raw RFC 5322 message bytes
283
+ * @returns Milter response with action, optional reply code, and headers
284
+ *
285
+ * @see Requirements 7.3, 7.4, 7.5
286
+ */
287
+ async milterCheck(rawMessage) {
288
+ const scanResult = await this.scan(rawMessage);
289
+ switch (scanResult.classification) {
290
+ case brightchain_lib_1.SpamClassification.DefiniteSpam:
291
+ // Req 7.3: reject at SMTP time with 550
292
+ return {
293
+ action: 'reject',
294
+ replyCode: 550,
295
+ replyText: '5.7.1 Message rejected as spam',
296
+ scanResult,
297
+ };
298
+ case brightchain_lib_1.SpamClassification.ProbableSpam:
299
+ // Req 7.4: accept and tag metadata with spam flag and score
300
+ return {
301
+ action: 'continue',
302
+ addHeaders: {
303
+ 'X-Spam-Flag': 'YES',
304
+ 'X-Spam-Score': scanResult.score.toFixed(2),
305
+ 'X-Spam-Status': `Yes, score=${scanResult.score.toFixed(2)}${scanResult.details ? ` tests=${scanResult.details}` : ''}`,
306
+ },
307
+ scanResult,
308
+ };
309
+ case brightchain_lib_1.SpamClassification.Ham:
310
+ default:
311
+ // Ham: accept without modification
312
+ return {
313
+ action: 'accept',
314
+ addHeaders: {
315
+ 'X-Spam-Flag': 'NO',
316
+ 'X-Spam-Score': scanResult.score.toFixed(2),
317
+ 'X-Spam-Status': `No, score=${scanResult.score.toFixed(2)}${scanResult.details ? ` tests=${scanResult.details}` : ''}`,
318
+ },
319
+ scanResult,
320
+ };
321
+ }
322
+ }
323
+ }
324
+ exports.AntiSpamFilter = AntiSpamFilter;
325
+ //# sourceMappingURL=antiSpamFilter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"antiSpamFilter.js","sourceRoot":"","sources":["../../../../../../brightchain-api-lib/src/lib/services/emailGateway/antiSpamFilter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,171 @@
1
+ /**
2
+ * BounceProcessor — parses DSN (Delivery Status Notification) messages
3
+ * per RFC 3464, correlates them to original outbound messages, updates
4
+ * delivery status, and notifies the original sender via Gossip Protocol.
5
+ *
6
+ * DSN correlation strategy:
7
+ * 1. Extract `Original-Message-ID` or `Message-ID` from the DSN body
8
+ * 2. Parse VERP-encoded bounce address to extract original message ID
9
+ * (e.g. `bounces+msgid=domain@canonical.domain`)
10
+ * 3. Fall back to fixed bounce address matching
11
+ *
12
+ * On permanent failure (5xx / "failed" action):
13
+ * - Update delivery status to FAILED in the metadata store
14
+ * - Generate an IBounceNotification and deliver to the original sender
15
+ * via the Gossip Protocol
16
+ *
17
+ * On transient failure (4xx / "delayed" action):
18
+ * - Record the transient bounce but do not mark as permanently failed
19
+ *
20
+ * @see Requirements 5.1, 5.2, 5.3, 5.4
21
+ * @module bounceProcessor
22
+ */
23
+ import type { IGossipService } from '@brightchain/brightchain-lib';
24
+ import { EmailMessageService } from '@brightchain/brightchain-lib';
25
+ import type { IEmailGatewayConfig } from './emailGatewayConfig';
26
+ import type { IOutboundQueueStore } from './outboundQueueStore';
27
+ /**
28
+ * Parsed result from a DSN message (RFC 3464).
29
+ */
30
+ export interface IParsedDsn {
31
+ /** The original Message-ID that this DSN refers to */
32
+ originalMessageId: string | undefined;
33
+ /** The recipient address that bounced */
34
+ recipientAddress: string | undefined;
35
+ /** DSN action: failed, delayed, delivered, relayed, expanded */
36
+ action: 'failed' | 'delayed' | 'delivered' | 'relayed' | 'expanded' | undefined;
37
+ /** SMTP diagnostic code (e.g. "550 5.1.1 User unknown") */
38
+ diagnosticCode: string | undefined;
39
+ /** SMTP status code (e.g. "5.1.1") */
40
+ statusCode: string | undefined;
41
+ /** The envelope-to / return-path from the DSN */
42
+ envelopeSender: string | undefined;
43
+ }
44
+ /**
45
+ * Interface for the BounceProcessor to allow dependency injection in tests.
46
+ */
47
+ export interface IBounceProcessor {
48
+ /**
49
+ * Process a raw DSN message.
50
+ *
51
+ * @param rawDsn - The raw RFC 3464 DSN message content
52
+ * @param envelopeSender - Optional envelope sender (Return-Path) for VERP correlation
53
+ */
54
+ processDsn(rawDsn: string | Uint8Array, envelopeSender?: string): Promise<void>;
55
+ }
56
+ /**
57
+ * Processes DSN (Delivery Status Notification) messages to track bounce
58
+ * status for outbound email.
59
+ *
60
+ * @see Requirements 5.1, 5.2, 5.3, 5.4
61
+ */
62
+ export declare class BounceProcessor implements IBounceProcessor {
63
+ private readonly config;
64
+ private readonly emailMessageService;
65
+ private readonly outboundQueueStore;
66
+ private readonly gossipService;
67
+ constructor(config: IEmailGatewayConfig, emailMessageService: EmailMessageService, outboundQueueStore: IOutboundQueueStore, gossipService: IGossipService);
68
+ /**
69
+ * Process a raw DSN message.
70
+ *
71
+ * Pipeline:
72
+ * 1. Parse the DSN to extract original message ID, recipient, action, and diagnostic
73
+ * 2. Correlate to the original outbound message via Message-ID or VERP
74
+ * 3. On permanent failure: update delivery status to FAILED, notify sender via gossip
75
+ * 4. On transient failure: log but do not mark as permanently failed
76
+ *
77
+ * @param rawDsn - The raw RFC 3464 DSN message content (string or bytes)
78
+ * @param envelopeSender - Optional envelope sender (Return-Path) for VERP correlation
79
+ *
80
+ * @see Requirements 5.1, 5.2, 5.3, 5.4
81
+ */
82
+ processDsn(rawDsn: string | Uint8Array, envelopeSender?: string): Promise<void>;
83
+ /**
84
+ * Parse a raw DSN message (RFC 3464) to extract the original message
85
+ * identifier, recipient address, action, and diagnostic code.
86
+ *
87
+ * RFC 3464 DSN messages are multipart/report with:
88
+ * - Part 1: Human-readable explanation
89
+ * - Part 2: message/delivery-status with per-recipient fields
90
+ * - Part 3: (optional) original message or headers
91
+ *
92
+ * This parser extracts key fields from the delivery-status part using
93
+ * simple line-based parsing (no full MIME parser needed for DSN fields).
94
+ *
95
+ * @param dsnText - The raw DSN message as a string
96
+ * @returns Parsed DSN fields
97
+ *
98
+ * @see Requirement 5.1
99
+ */
100
+ static parseDsnMessage(dsnText: string): IParsedDsn;
101
+ /**
102
+ * Parse a VERP (Variable Envelope Return Path) encoded bounce address
103
+ * to extract the original message identifier.
104
+ *
105
+ * VERP format: `bounces+<encoded-msgid>=<encoded-domain>@<canonical-domain>`
106
+ *
107
+ * Examples:
108
+ * - `bounces+abc123=example.com@brightchain.org` → `<abc123@example.com>`
109
+ * - `bounces+msg-001=mail.test.org@brightchain.org` → `<msg-001@mail.test.org>`
110
+ *
111
+ * @param bounceAddress - The envelope sender / Return-Path address
112
+ * @param canonicalDomain - The canonical domain to validate against
113
+ * @returns The extracted original Message-ID, or undefined if not VERP-encoded
114
+ *
115
+ * @see Requirement 5.4
116
+ */
117
+ static parseVerpAddress(bounceAddress: string, canonicalDomain: string): string | undefined;
118
+ /**
119
+ * Classify a parsed DSN as permanent or transient bounce.
120
+ *
121
+ * - Action "failed" or status code starting with "5" → permanent
122
+ * - Action "delayed" or status code starting with "4" → transient
123
+ * - Default: permanent (fail-safe)
124
+ *
125
+ * @param parsed - The parsed DSN fields
126
+ * @returns 'permanent' or 'transient'
127
+ */
128
+ static classifyBounce(parsed: IParsedDsn): 'permanent' | 'transient';
129
+ /**
130
+ * Correlate a parsed DSN to the original outbound message.
131
+ *
132
+ * Strategy (in order):
133
+ * 1. Use `originalMessageId` extracted from DSN headers
134
+ * 2. Parse VERP-encoded envelope sender to extract message ID
135
+ * 3. Return undefined if correlation fails
136
+ *
137
+ * @param parsed - The parsed DSN fields
138
+ * @returns The original Message-ID, or undefined if correlation fails
139
+ *
140
+ * @see Requirement 5.4
141
+ */
142
+ private correlateToOriginal;
143
+ /**
144
+ * Update the delivery status of the original message to FAILED.
145
+ *
146
+ * Updates both:
147
+ * - The outbound queue store (OutboundDeliveryStatus.PermanentFailure)
148
+ * - The email metadata store (DeliveryStatus.Failed on the delivery receipt)
149
+ *
150
+ * @param messageId - The original Message-ID
151
+ * @param recipientAddress - The recipient that bounced
152
+ * @param failureReason - Human-readable failure reason
153
+ *
154
+ * @see Requirement 5.2
155
+ */
156
+ private updateDeliveryStatusToFailed;
157
+ /**
158
+ * Find the key in the delivery receipts map that matches a recipient address.
159
+ */
160
+ private findRecipientKey;
161
+ /**
162
+ * Generate a bounce notification and deliver it to the original sender
163
+ * via the Gossip Protocol.
164
+ *
165
+ * @param notification - The bounce notification to deliver
166
+ *
167
+ * @see Requirement 5.3
168
+ */
169
+ private sendBounceNotification;
170
+ }
171
+ //# sourceMappingURL=bounceProcessor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bounceProcessor.d.ts","sourceRoot":"","sources":["../../../../../../brightchain-api-lib/src/lib/services/emailGateway/bounceProcessor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,KAAK,EAEV,cAAc,EACf,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAEL,mBAAmB,EACpB,MAAM,8BAA8B,CAAC;AAEtC,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAChE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAIhE;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,sDAAsD;IACtD,iBAAiB,EAAE,MAAM,GAAG,SAAS,CAAC;IAEtC,yCAAyC;IACzC,gBAAgB,EAAE,MAAM,GAAG,SAAS,CAAC;IAErC,gEAAgE;IAChE,MAAM,EACF,QAAQ,GACR,SAAS,GACT,WAAW,GACX,SAAS,GACT,UAAU,GACV,SAAS,CAAC;IAEd,2DAA2D;IAC3D,cAAc,EAAE,MAAM,GAAG,SAAS,CAAC;IAEnC,sCAAsC;IACtC,UAAU,EAAE,MAAM,GAAG,SAAS,CAAC;IAE/B,iDAAiD;IACjD,cAAc,EAAE,MAAM,GAAG,SAAS,CAAC;CACpC;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B;;;;;OAKG;IACH,UAAU,CACR,MAAM,EAAE,MAAM,GAAG,UAAU,EAC3B,cAAc,CAAC,EAAE,MAAM,GACtB,OAAO,CAAC,IAAI,CAAC,CAAC;CAClB;AAID;;;;;GAKG;AACH,qBAAa,eAAgB,YAAW,gBAAgB;IAEpD,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,mBAAmB;IACpC,OAAO,CAAC,QAAQ,CAAC,kBAAkB;IACnC,OAAO,CAAC,QAAQ,CAAC,aAAa;gBAHb,MAAM,EAAE,mBAAmB,EAC3B,mBAAmB,EAAE,mBAAmB,EACxC,kBAAkB,EAAE,mBAAmB,EACvC,aAAa,EAAE,cAAc;IAKhD;;;;;;;;;;;;;OAaG;IACG,UAAU,CACd,MAAM,EAAE,MAAM,GAAG,UAAU,EAC3B,cAAc,CAAC,EAAE,MAAM,GACtB,OAAO,CAAC,IAAI,CAAC;IAiDhB;;;;;;;;;;;;;;;;OAgBG;IACH,MAAM,CAAC,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,UAAU;IAuFnD;;;;;;;;;;;;;;;OAeG;IACH,MAAM,CAAC,gBAAgB,CACrB,aAAa,EAAE,MAAM,EACrB,eAAe,EAAE,MAAM,GACtB,MAAM,GAAG,SAAS;IAiCrB;;;;;;;;;OASG;IACH,MAAM,CAAC,cAAc,CAAC,MAAM,EAAE,UAAU,GAAG,WAAW,GAAG,WAAW;IAgBpE;;;;;;;;;;;;OAYG;YACW,mBAAmB;IAkCjC;;;;;;;;;;;;OAYG;YACW,4BAA4B;IAgD1C;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAaxB;;;;;;;OAOG;YACW,sBAAsB;CAkCrC"}