@push.rocks/smartmta 5.1.3 → 5.2.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 (98) hide show
  1. package/changelog.md +7 -0
  2. package/dist_ts/00_commitinfo_data.d.ts +8 -0
  3. package/dist_ts/00_commitinfo_data.js +9 -0
  4. package/dist_ts/index.d.ts +3 -0
  5. package/dist_ts/index.js +4 -0
  6. package/dist_ts/logger.d.ts +17 -0
  7. package/dist_ts/logger.js +76 -0
  8. package/dist_ts/mail/core/classes.bouncemanager.d.ts +185 -0
  9. package/dist_ts/mail/core/classes.bouncemanager.js +569 -0
  10. package/dist_ts/mail/core/classes.email.d.ts +291 -0
  11. package/dist_ts/mail/core/classes.email.js +802 -0
  12. package/dist_ts/mail/core/classes.emailvalidator.d.ts +61 -0
  13. package/dist_ts/mail/core/classes.emailvalidator.js +184 -0
  14. package/dist_ts/mail/core/classes.templatemanager.d.ts +95 -0
  15. package/dist_ts/mail/core/classes.templatemanager.js +240 -0
  16. package/dist_ts/mail/core/index.d.ts +4 -0
  17. package/dist_ts/mail/core/index.js +6 -0
  18. package/dist_ts/mail/delivery/classes.delivery.queue.d.ts +163 -0
  19. package/dist_ts/mail/delivery/classes.delivery.queue.js +488 -0
  20. package/dist_ts/mail/delivery/classes.delivery.system.d.ts +160 -0
  21. package/dist_ts/mail/delivery/classes.delivery.system.js +630 -0
  22. package/dist_ts/mail/delivery/classes.unified.rate.limiter.d.ts +200 -0
  23. package/dist_ts/mail/delivery/classes.unified.rate.limiter.js +820 -0
  24. package/dist_ts/mail/delivery/index.d.ts +4 -0
  25. package/dist_ts/mail/delivery/index.js +6 -0
  26. package/dist_ts/mail/delivery/interfaces.d.ts +140 -0
  27. package/dist_ts/mail/delivery/interfaces.js +17 -0
  28. package/dist_ts/mail/index.d.ts +7 -0
  29. package/dist_ts/mail/index.js +12 -0
  30. package/dist_ts/mail/routing/classes.dkim.manager.d.ts +25 -0
  31. package/dist_ts/mail/routing/classes.dkim.manager.js +127 -0
  32. package/dist_ts/mail/routing/classes.dns.manager.d.ts +79 -0
  33. package/dist_ts/mail/routing/classes.dns.manager.js +415 -0
  34. package/dist_ts/mail/routing/classes.domain.registry.d.ts +54 -0
  35. package/dist_ts/mail/routing/classes.domain.registry.js +119 -0
  36. package/dist_ts/mail/routing/classes.email.action.executor.d.ts +33 -0
  37. package/dist_ts/mail/routing/classes.email.action.executor.js +137 -0
  38. package/dist_ts/mail/routing/classes.email.router.d.ts +171 -0
  39. package/dist_ts/mail/routing/classes.email.router.js +494 -0
  40. package/dist_ts/mail/routing/classes.unified.email.server.d.ts +241 -0
  41. package/dist_ts/mail/routing/classes.unified.email.server.js +935 -0
  42. package/dist_ts/mail/routing/index.d.ts +7 -0
  43. package/dist_ts/mail/routing/index.js +9 -0
  44. package/dist_ts/mail/routing/interfaces.d.ts +187 -0
  45. package/dist_ts/mail/routing/interfaces.js +2 -0
  46. package/dist_ts/mail/security/classes.dkimcreator.d.ts +72 -0
  47. package/dist_ts/mail/security/classes.dkimcreator.js +360 -0
  48. package/dist_ts/mail/security/classes.spfverifier.d.ts +62 -0
  49. package/dist_ts/mail/security/classes.spfverifier.js +87 -0
  50. package/dist_ts/mail/security/index.d.ts +2 -0
  51. package/dist_ts/mail/security/index.js +4 -0
  52. package/dist_ts/paths.d.ts +14 -0
  53. package/dist_ts/paths.js +39 -0
  54. package/dist_ts/plugins.d.ts +24 -0
  55. package/dist_ts/plugins.js +28 -0
  56. package/dist_ts/security/classes.contentscanner.d.ts +130 -0
  57. package/dist_ts/security/classes.contentscanner.js +338 -0
  58. package/dist_ts/security/classes.ipreputationchecker.d.ts +73 -0
  59. package/dist_ts/security/classes.ipreputationchecker.js +263 -0
  60. package/dist_ts/security/classes.rustsecuritybridge.d.ts +398 -0
  61. package/dist_ts/security/classes.rustsecuritybridge.js +484 -0
  62. package/dist_ts/security/classes.securitylogger.d.ts +140 -0
  63. package/dist_ts/security/classes.securitylogger.js +235 -0
  64. package/dist_ts/security/index.d.ts +4 -0
  65. package/dist_ts/security/index.js +5 -0
  66. package/package.json +6 -1
  67. package/ts/00_commitinfo_data.ts +8 -0
  68. package/ts/index.ts +3 -0
  69. package/ts/logger.ts +91 -0
  70. package/ts/mail/core/classes.bouncemanager.ts +731 -0
  71. package/ts/mail/core/classes.email.ts +942 -0
  72. package/ts/mail/core/classes.emailvalidator.ts +239 -0
  73. package/ts/mail/core/classes.templatemanager.ts +320 -0
  74. package/ts/mail/core/index.ts +5 -0
  75. package/ts/mail/delivery/classes.delivery.queue.ts +645 -0
  76. package/ts/mail/delivery/classes.delivery.system.ts +816 -0
  77. package/ts/mail/delivery/classes.unified.rate.limiter.ts +1053 -0
  78. package/ts/mail/delivery/index.ts +5 -0
  79. package/ts/mail/delivery/interfaces.ts +167 -0
  80. package/ts/mail/index.ts +17 -0
  81. package/ts/mail/routing/classes.dkim.manager.ts +157 -0
  82. package/ts/mail/routing/classes.dns.manager.ts +573 -0
  83. package/ts/mail/routing/classes.domain.registry.ts +139 -0
  84. package/ts/mail/routing/classes.email.action.executor.ts +175 -0
  85. package/ts/mail/routing/classes.email.router.ts +575 -0
  86. package/ts/mail/routing/classes.unified.email.server.ts +1207 -0
  87. package/ts/mail/routing/index.ts +9 -0
  88. package/ts/mail/routing/interfaces.ts +202 -0
  89. package/ts/mail/security/classes.dkimcreator.ts +447 -0
  90. package/ts/mail/security/classes.spfverifier.ts +126 -0
  91. package/ts/mail/security/index.ts +3 -0
  92. package/ts/paths.ts +48 -0
  93. package/ts/plugins.ts +53 -0
  94. package/ts/security/classes.contentscanner.ts +400 -0
  95. package/ts/security/classes.ipreputationchecker.ts +315 -0
  96. package/ts/security/classes.rustsecuritybridge.ts +943 -0
  97. package/ts/security/classes.securitylogger.ts +299 -0
  98. package/ts/security/index.ts +40 -0
@@ -0,0 +1,263 @@
1
+ import * as plugins from '../plugins.js';
2
+ import * as paths from '../paths.js';
3
+ import { logger } from '../logger.js';
4
+ import { SecurityLogger, SecurityLogLevel, SecurityEventType } from './classes.securitylogger.js';
5
+ import { RustSecurityBridge } from './classes.rustsecuritybridge.js';
6
+ import { LRUCache } from 'lru-cache';
7
+ /**
8
+ * Reputation threshold scores
9
+ */
10
+ export var ReputationThreshold;
11
+ (function (ReputationThreshold) {
12
+ ReputationThreshold[ReputationThreshold["HIGH_RISK"] = 20] = "HIGH_RISK";
13
+ ReputationThreshold[ReputationThreshold["MEDIUM_RISK"] = 50] = "MEDIUM_RISK";
14
+ ReputationThreshold[ReputationThreshold["LOW_RISK"] = 80] = "LOW_RISK"; // Score below this is considered low risk (but not trusted)
15
+ })(ReputationThreshold || (ReputationThreshold = {}));
16
+ /**
17
+ * IP type classifications
18
+ */
19
+ export var IPType;
20
+ (function (IPType) {
21
+ IPType["RESIDENTIAL"] = "residential";
22
+ IPType["DATACENTER"] = "datacenter";
23
+ IPType["PROXY"] = "proxy";
24
+ IPType["TOR"] = "tor";
25
+ IPType["VPN"] = "vpn";
26
+ IPType["UNKNOWN"] = "unknown";
27
+ })(IPType || (IPType = {}));
28
+ /**
29
+ * IP reputation checker — delegates DNSBL lookups to the Rust security bridge.
30
+ * Retains LRU caching and disk persistence in TypeScript.
31
+ */
32
+ export class IPReputationChecker {
33
+ static instance;
34
+ reputationCache;
35
+ options;
36
+ storageManager;
37
+ static DEFAULT_OPTIONS = {
38
+ maxCacheSize: 10000,
39
+ cacheTTL: 24 * 60 * 60 * 1000,
40
+ dnsblServers: [],
41
+ highRiskThreshold: ReputationThreshold.HIGH_RISK,
42
+ mediumRiskThreshold: ReputationThreshold.MEDIUM_RISK,
43
+ lowRiskThreshold: ReputationThreshold.LOW_RISK,
44
+ enableLocalCache: true,
45
+ enableDNSBL: true,
46
+ enableIPInfo: true
47
+ };
48
+ constructor(options = {}, storageManager) {
49
+ this.options = {
50
+ ...IPReputationChecker.DEFAULT_OPTIONS,
51
+ ...options
52
+ };
53
+ this.storageManager = storageManager;
54
+ this.reputationCache = new LRUCache({
55
+ max: this.options.maxCacheSize,
56
+ ttl: this.options.cacheTTL,
57
+ });
58
+ if (this.options.enableLocalCache) {
59
+ this.loadCache().catch(error => {
60
+ logger.log('error', `Failed to load IP reputation cache during initialization: ${error.message}`);
61
+ });
62
+ }
63
+ }
64
+ static getInstance(options = {}, storageManager) {
65
+ if (!IPReputationChecker.instance) {
66
+ IPReputationChecker.instance = new IPReputationChecker(options, storageManager);
67
+ }
68
+ return IPReputationChecker.instance;
69
+ }
70
+ /**
71
+ * Check an IP address's reputation via the Rust bridge
72
+ */
73
+ async checkReputation(ip) {
74
+ try {
75
+ if (!this.isValidIPAddress(ip)) {
76
+ logger.log('warn', `Invalid IP address format: ${ip}`);
77
+ return this.createErrorResult(ip, 'Invalid IP address format');
78
+ }
79
+ // Check cache first
80
+ const cachedResult = this.reputationCache.get(ip);
81
+ if (cachedResult) {
82
+ logger.log('info', `Using cached reputation data for IP ${ip}`, {
83
+ score: cachedResult.score,
84
+ isSpam: cachedResult.isSpam
85
+ });
86
+ return cachedResult;
87
+ }
88
+ // Delegate to Rust bridge
89
+ const bridge = RustSecurityBridge.getInstance();
90
+ const rustResult = await bridge.checkIpReputation(ip);
91
+ const result = {
92
+ score: rustResult.score,
93
+ isSpam: rustResult.listed_count > 0,
94
+ isProxy: rustResult.ip_type === 'proxy',
95
+ isTor: rustResult.ip_type === 'tor',
96
+ isVPN: rustResult.ip_type === 'vpn',
97
+ blacklists: rustResult.dnsbl_results
98
+ .filter(d => d.listed)
99
+ .map(d => d.server),
100
+ timestamp: Date.now(),
101
+ };
102
+ this.reputationCache.set(ip, result);
103
+ if (this.options.enableLocalCache) {
104
+ this.saveCache().catch(error => {
105
+ logger.log('error', `Failed to save IP reputation cache: ${error.message}`);
106
+ });
107
+ }
108
+ this.logReputationCheck(ip, result);
109
+ return result;
110
+ }
111
+ catch (error) {
112
+ logger.log('error', `Error checking IP reputation for ${ip}: ${error.message}`, {
113
+ ip,
114
+ stack: error.stack
115
+ });
116
+ const errorResult = this.createErrorResult(ip, error.message);
117
+ // Cache error results to avoid repeated failing lookups
118
+ this.reputationCache.set(ip, errorResult);
119
+ return errorResult;
120
+ }
121
+ }
122
+ createErrorResult(ip, errorMessage) {
123
+ return {
124
+ score: 50,
125
+ isSpam: false,
126
+ isProxy: false,
127
+ isTor: false,
128
+ isVPN: false,
129
+ timestamp: Date.now(),
130
+ error: errorMessage
131
+ };
132
+ }
133
+ isValidIPAddress(ip) {
134
+ const ipv4Pattern = /^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;
135
+ return ipv4Pattern.test(ip);
136
+ }
137
+ logReputationCheck(ip, result) {
138
+ let logLevel = SecurityLogLevel.INFO;
139
+ if (result.score < this.options.highRiskThreshold) {
140
+ logLevel = SecurityLogLevel.WARN;
141
+ }
142
+ SecurityLogger.getInstance().logEvent({
143
+ level: logLevel,
144
+ type: SecurityEventType.IP_REPUTATION,
145
+ message: `IP reputation check ${result.isSpam ? 'flagged spam' : 'completed'} for ${ip}`,
146
+ ipAddress: ip,
147
+ details: {
148
+ score: result.score,
149
+ isSpam: result.isSpam,
150
+ isProxy: result.isProxy,
151
+ isTor: result.isTor,
152
+ isVPN: result.isVPN,
153
+ country: result.country,
154
+ blacklists: result.blacklists
155
+ },
156
+ success: !result.isSpam
157
+ });
158
+ }
159
+ async saveCache() {
160
+ try {
161
+ const entries = Array.from(this.reputationCache.entries()).map(([ip, data]) => ({
162
+ ip,
163
+ data
164
+ }));
165
+ if (entries.length === 0) {
166
+ return;
167
+ }
168
+ const cacheData = JSON.stringify(entries);
169
+ if (this.storageManager) {
170
+ await this.storageManager.set('/security/ip-reputation-cache.json', cacheData);
171
+ logger.log('info', `Saved ${entries.length} IP reputation cache entries to StorageManager`);
172
+ }
173
+ else {
174
+ const cacheDir = plugins.path.join(paths.dataDir, 'security');
175
+ await plugins.smartfs.directory(cacheDir).recursive().create();
176
+ const cacheFile = plugins.path.join(cacheDir, 'ip_reputation_cache.json');
177
+ await plugins.smartfs.file(cacheFile).write(cacheData);
178
+ logger.log('info', `Saved ${entries.length} IP reputation cache entries to disk`);
179
+ }
180
+ }
181
+ catch (error) {
182
+ logger.log('error', `Failed to save IP reputation cache: ${error.message}`);
183
+ }
184
+ }
185
+ async loadCache() {
186
+ try {
187
+ let cacheData = null;
188
+ let fromFilesystem = false;
189
+ if (this.storageManager) {
190
+ try {
191
+ cacheData = await this.storageManager.get('/security/ip-reputation-cache.json');
192
+ if (!cacheData) {
193
+ const cacheFile = plugins.path.join(paths.dataDir, 'security', 'ip_reputation_cache.json');
194
+ if (plugins.fs.existsSync(cacheFile)) {
195
+ logger.log('info', 'Migrating IP reputation cache from filesystem to StorageManager');
196
+ cacheData = plugins.fs.readFileSync(cacheFile, 'utf8');
197
+ fromFilesystem = true;
198
+ await this.storageManager.set('/security/ip-reputation-cache.json', cacheData);
199
+ logger.log('info', 'IP reputation cache migrated to StorageManager successfully');
200
+ try {
201
+ plugins.fs.unlinkSync(cacheFile);
202
+ logger.log('info', 'Old cache file removed after migration');
203
+ }
204
+ catch (deleteError) {
205
+ logger.log('warn', `Could not delete old cache file: ${deleteError.message}`);
206
+ }
207
+ }
208
+ }
209
+ }
210
+ catch (error) {
211
+ logger.log('error', `Error loading from StorageManager: ${error.message}`);
212
+ }
213
+ }
214
+ else {
215
+ const cacheFile = plugins.path.join(paths.dataDir, 'security', 'ip_reputation_cache.json');
216
+ if (plugins.fs.existsSync(cacheFile)) {
217
+ cacheData = plugins.fs.readFileSync(cacheFile, 'utf8');
218
+ fromFilesystem = true;
219
+ }
220
+ }
221
+ if (cacheData) {
222
+ const entries = JSON.parse(cacheData);
223
+ const now = Date.now();
224
+ const validEntries = entries.filter(entry => {
225
+ const age = now - entry.data.timestamp;
226
+ return age < this.options.cacheTTL;
227
+ });
228
+ for (const entry of validEntries) {
229
+ this.reputationCache.set(entry.ip, entry.data);
230
+ }
231
+ const source = fromFilesystem ? 'disk' : 'StorageManager';
232
+ logger.log('info', `Loaded ${validEntries.length} IP reputation cache entries from ${source}`);
233
+ }
234
+ }
235
+ catch (error) {
236
+ logger.log('error', `Failed to load IP reputation cache: ${error.message}`);
237
+ }
238
+ }
239
+ static getRiskLevel(score) {
240
+ if (score < ReputationThreshold.HIGH_RISK) {
241
+ return 'high';
242
+ }
243
+ else if (score < ReputationThreshold.MEDIUM_RISK) {
244
+ return 'medium';
245
+ }
246
+ else if (score < ReputationThreshold.LOW_RISK) {
247
+ return 'low';
248
+ }
249
+ else {
250
+ return 'trusted';
251
+ }
252
+ }
253
+ updateStorageManager(storageManager) {
254
+ this.storageManager = storageManager;
255
+ logger.log('info', 'IPReputationChecker storage manager updated');
256
+ if (this.options.enableLocalCache && this.reputationCache.size > 0) {
257
+ this.saveCache().catch(error => {
258
+ logger.log('error', `Failed to save cache to new storage manager: ${error.message}`);
259
+ });
260
+ }
261
+ }
262
+ }
263
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5pcHJlcHV0YXRpb25jaGVja2VyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vdHMvc2VjdXJpdHkvY2xhc3Nlcy5pcHJlcHV0YXRpb25jaGVja2VyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxPQUFPLE1BQU0sZUFBZSxDQUFDO0FBQ3pDLE9BQU8sS0FBSyxLQUFLLE1BQU0sYUFBYSxDQUFDO0FBQ3JDLE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSxjQUFjLENBQUM7QUFDdEMsT0FBTyxFQUFFLGNBQWMsRUFBRSxnQkFBZ0IsRUFBRSxpQkFBaUIsRUFBRSxNQUFNLDZCQUE2QixDQUFDO0FBQ2xHLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLGlDQUFpQyxDQUFDO0FBQ3JFLE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBTSxXQUFXLENBQUM7QUFtQnJDOztHQUVHO0FBQ0gsTUFBTSxDQUFOLElBQVksbUJBSVg7QUFKRCxXQUFZLG1CQUFtQjtJQUM3Qix3RUFBYyxDQUFBO0lBQ2QsNEVBQWdCLENBQUE7SUFDaEIsc0VBQWEsQ0FBQSxDQUFRLDREQUE0RDtBQUNuRixDQUFDLEVBSlcsbUJBQW1CLEtBQW5CLG1CQUFtQixRQUk5QjtBQUVEOztHQUVHO0FBQ0gsTUFBTSxDQUFOLElBQVksTUFPWDtBQVBELFdBQVksTUFBTTtJQUNoQixxQ0FBMkIsQ0FBQTtJQUMzQixtQ0FBeUIsQ0FBQTtJQUN6Qix5QkFBZSxDQUFBO0lBQ2YscUJBQVcsQ0FBQTtJQUNYLHFCQUFXLENBQUE7SUFDWCw2QkFBbUIsQ0FBQTtBQUNyQixDQUFDLEVBUFcsTUFBTSxLQUFOLE1BQU0sUUFPakI7QUFpQkQ7OztHQUdHO0FBQ0gsTUFBTSxPQUFPLG1CQUFtQjtJQUN0QixNQUFNLENBQUMsUUFBUSxDQUFzQjtJQUNyQyxlQUFlLENBQXNDO0lBQ3JELE9BQU8sQ0FBaUM7SUFDeEMsY0FBYyxDQUFPO0lBRXJCLE1BQU0sQ0FBVSxl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
@@ -0,0 +1,398 @@
1
+ import { EventEmitter } from 'events';
2
+ interface IDkimVerificationResult {
3
+ is_valid: boolean;
4
+ domain: string | null;
5
+ selector: string | null;
6
+ status: string;
7
+ details: string | null;
8
+ }
9
+ interface ISpfResult {
10
+ result: string;
11
+ domain: string;
12
+ ip: string;
13
+ explanation: string | null;
14
+ }
15
+ interface IDmarcResult {
16
+ passed: boolean;
17
+ policy: string;
18
+ domain: string;
19
+ dkim_result: string;
20
+ spf_result: string;
21
+ action: string;
22
+ details: string | null;
23
+ }
24
+ interface IEmailSecurityResult {
25
+ dkim: IDkimVerificationResult[];
26
+ spf: ISpfResult | null;
27
+ dmarc: IDmarcResult | null;
28
+ }
29
+ interface IValidationResult {
30
+ valid: boolean;
31
+ formatValid: boolean;
32
+ score: number;
33
+ error: string | null;
34
+ }
35
+ interface IBounceDetection {
36
+ bounce_type: string;
37
+ category: string;
38
+ }
39
+ interface IReputationResult {
40
+ ip: string;
41
+ score: number;
42
+ risk_level: string;
43
+ ip_type: string;
44
+ dnsbl_results: Array<{
45
+ server: string;
46
+ listed: boolean;
47
+ response: string | null;
48
+ }>;
49
+ listed_count: number;
50
+ total_checked: number;
51
+ }
52
+ interface IContentScanResult {
53
+ threatScore: number;
54
+ threatType: string | null;
55
+ threatDetails: string | null;
56
+ scannedElements: string[];
57
+ }
58
+ interface IOutboundEmail {
59
+ from: string;
60
+ to: string[];
61
+ cc?: string[];
62
+ bcc?: string[];
63
+ subject?: string;
64
+ text?: string;
65
+ html?: string;
66
+ headers?: Record<string, string>;
67
+ }
68
+ interface ISmtpSendResult {
69
+ accepted: string[];
70
+ rejected: string[];
71
+ messageId?: string;
72
+ response: string;
73
+ envelope: {
74
+ from: string;
75
+ to: string[];
76
+ };
77
+ }
78
+ interface ISmtpSendOptions {
79
+ host: string;
80
+ port: number;
81
+ secure?: boolean;
82
+ domain?: string;
83
+ auth?: {
84
+ user: string;
85
+ pass: string;
86
+ method?: string;
87
+ };
88
+ email: IOutboundEmail;
89
+ dkim?: {
90
+ domain: string;
91
+ selector: string;
92
+ privateKey: string;
93
+ keyType?: string;
94
+ };
95
+ connectionTimeoutSecs?: number;
96
+ socketTimeoutSecs?: number;
97
+ poolKey?: string;
98
+ maxPoolConnections?: number;
99
+ tlsOpportunistic?: boolean;
100
+ }
101
+ interface ISmtpSendRawOptions {
102
+ host: string;
103
+ port: number;
104
+ secure?: boolean;
105
+ domain?: string;
106
+ auth?: {
107
+ user: string;
108
+ pass: string;
109
+ method?: string;
110
+ };
111
+ envelopeFrom: string;
112
+ envelopeTo: string[];
113
+ rawMessageBase64: string;
114
+ poolKey?: string;
115
+ }
116
+ interface ISmtpVerifyOptions {
117
+ host: string;
118
+ port: number;
119
+ secure?: boolean;
120
+ domain?: string;
121
+ auth?: {
122
+ user: string;
123
+ pass: string;
124
+ method?: string;
125
+ };
126
+ }
127
+ interface ISmtpVerifyResult {
128
+ reachable: boolean;
129
+ greeting?: string;
130
+ capabilities?: string[];
131
+ }
132
+ interface ISmtpPoolStatus {
133
+ pools: Record<string, {
134
+ total: number;
135
+ active: number;
136
+ idle: number;
137
+ }>;
138
+ }
139
+ interface IVersionInfo {
140
+ bin: string;
141
+ core: string;
142
+ security: string;
143
+ smtp: string;
144
+ }
145
+ interface ISmtpServerConfig {
146
+ hostname: string;
147
+ ports: number[];
148
+ securePort?: number;
149
+ tlsCertPem?: string;
150
+ tlsKeyPem?: string;
151
+ additionalTlsCerts?: Array<{
152
+ domains: string[];
153
+ certPem: string;
154
+ keyPem: string;
155
+ }>;
156
+ maxMessageSize?: number;
157
+ maxConnections?: number;
158
+ maxRecipients?: number;
159
+ connectionTimeoutSecs?: number;
160
+ dataTimeoutSecs?: number;
161
+ authEnabled?: boolean;
162
+ maxAuthFailures?: number;
163
+ socketTimeoutSecs?: number;
164
+ processingTimeoutSecs?: number;
165
+ rateLimits?: IRateLimitConfig;
166
+ }
167
+ interface IRateLimitConfig {
168
+ maxConnectionsPerIp?: number;
169
+ maxMessagesPerSender?: number;
170
+ maxAuthFailuresPerIp?: number;
171
+ windowSecs?: number;
172
+ }
173
+ interface IEmailData {
174
+ type: 'inline' | 'file';
175
+ base64?: string;
176
+ path?: string;
177
+ }
178
+ interface IEmailReceivedEvent {
179
+ correlationId: string;
180
+ sessionId: string;
181
+ mailFrom: string;
182
+ rcptTo: string[];
183
+ data: IEmailData;
184
+ remoteAddr: string;
185
+ clientHostname: string | null;
186
+ secure: boolean;
187
+ authenticatedUser: string | null;
188
+ securityResults: any | null;
189
+ }
190
+ interface IAuthRequestEvent {
191
+ correlationId: string;
192
+ sessionId: string;
193
+ username: string;
194
+ password: string;
195
+ remoteAddr: string;
196
+ }
197
+ interface IScramCredentialRequestEvent {
198
+ correlationId: string;
199
+ sessionId: string;
200
+ username: string;
201
+ remoteAddr: string;
202
+ }
203
+ export declare enum BridgeState {
204
+ Idle = "idle",
205
+ Starting = "starting",
206
+ Running = "running",
207
+ Restarting = "restarting",
208
+ Failed = "failed",
209
+ Stopped = "stopped"
210
+ }
211
+ export interface IBridgeResilienceConfig {
212
+ maxRestartAttempts: number;
213
+ healthCheckIntervalMs: number;
214
+ restartBackoffBaseMs: number;
215
+ restartBackoffMaxMs: number;
216
+ healthCheckTimeoutMs: number;
217
+ }
218
+ /**
219
+ * Bridge between TypeScript and the Rust `mailer-bin` binary.
220
+ *
221
+ * Uses `@push.rocks/smartrust` for JSON-over-stdin/stdout IPC.
222
+ * Singleton — access via `RustSecurityBridge.getInstance()`.
223
+ *
224
+ * Features resilience via auto-restart with exponential backoff,
225
+ * periodic health checks, and a state machine that tracks the
226
+ * bridge lifecycle.
227
+ */
228
+ export declare class RustSecurityBridge extends EventEmitter {
229
+ private static instance;
230
+ private static _resilienceConfig;
231
+ private bridge;
232
+ private _running;
233
+ private _state;
234
+ private _restartAttempts;
235
+ private _restartTimer;
236
+ private _healthCheckTimer;
237
+ private _deliberateStop;
238
+ private _smtpServerConfig;
239
+ private constructor();
240
+ /** Get or create the singleton instance. */
241
+ static getInstance(): RustSecurityBridge;
242
+ /** Reset the singleton instance (for testing). */
243
+ static resetInstance(): void;
244
+ /** Configure resilience parameters. Can be called before or after getInstance(). */
245
+ static configure(config: Partial<IBridgeResilienceConfig>): void;
246
+ /** Current bridge state. */
247
+ get state(): BridgeState;
248
+ /** Whether the Rust process is currently running and accepting commands. */
249
+ get running(): boolean;
250
+ private setState;
251
+ /**
252
+ * Throws a descriptive error if the bridge is not in Running state.
253
+ * Called at the top of every command method.
254
+ */
255
+ private ensureRunning;
256
+ /**
257
+ * Spawn the Rust binary and wait for the ready signal.
258
+ * @returns `true` if the binary started successfully, `false` otherwise.
259
+ */
260
+ start(): Promise<boolean>;
261
+ /** Kill the Rust process deliberately. */
262
+ stop(): Promise<void>;
263
+ private attemptRestart;
264
+ /**
265
+ * Restore state after a successful restart:
266
+ * - Re-send startSmtpServer command if the SMTP server was running
267
+ */
268
+ private restoreAfterRestart;
269
+ private startHealthCheck;
270
+ private stopHealthCheck;
271
+ /** Ping the Rust process. */
272
+ ping(): Promise<boolean>;
273
+ /** Get version information for all Rust crates. */
274
+ getVersion(): Promise<IVersionInfo>;
275
+ /** Validate an email address. */
276
+ validateEmail(email: string): Promise<IValidationResult>;
277
+ /** Detect bounce type from SMTP response / diagnostic code. */
278
+ detectBounce(opts: {
279
+ smtpResponse?: string;
280
+ diagnosticCode?: string;
281
+ statusCode?: string;
282
+ }): Promise<IBounceDetection>;
283
+ /** Scan email content for threats (phishing, spam, malware, etc.). */
284
+ scanContent(opts: {
285
+ subject?: string;
286
+ textBody?: string;
287
+ htmlBody?: string;
288
+ attachmentNames?: string[];
289
+ }): Promise<IContentScanResult>;
290
+ /** Check IP reputation via DNSBL. */
291
+ checkIpReputation(ip: string): Promise<IReputationResult>;
292
+ /** Verify DKIM signatures on a raw email message. */
293
+ verifyDkim(rawMessage: string): Promise<IDkimVerificationResult[]>;
294
+ /** Sign an email with DKIM (RSA or Ed25519). */
295
+ signDkim(opts: {
296
+ rawMessage: string;
297
+ domain: string;
298
+ selector?: string;
299
+ privateKey: string;
300
+ keyType?: string;
301
+ }): Promise<{
302
+ header: string;
303
+ signedMessage: string;
304
+ }>;
305
+ /** Check SPF for a sender. */
306
+ checkSpf(opts: {
307
+ ip: string;
308
+ heloDomain: string;
309
+ hostname?: string;
310
+ mailFrom: string;
311
+ }): Promise<ISpfResult>;
312
+ /**
313
+ * Compound email security verification: DKIM + SPF + DMARC in one IPC call.
314
+ *
315
+ * This is the preferred method for inbound email verification — it avoids
316
+ * 3 sequential round-trips and correctly passes raw mail-auth types internally.
317
+ */
318
+ verifyEmail(opts: {
319
+ rawMessage: string;
320
+ ip: string;
321
+ heloDomain: string;
322
+ hostname?: string;
323
+ mailFrom: string;
324
+ }): Promise<IEmailSecurityResult>;
325
+ /** Send a structured email via the Rust SMTP client. */
326
+ sendOutboundEmail(opts: ISmtpSendOptions): Promise<ISmtpSendResult>;
327
+ /** Send a pre-formatted raw email via the Rust SMTP client. */
328
+ sendRawEmail(opts: ISmtpSendRawOptions): Promise<ISmtpSendResult>;
329
+ /** Verify connectivity to an SMTP server. */
330
+ verifySmtpConnection(opts: ISmtpVerifyOptions): Promise<ISmtpVerifyResult>;
331
+ /** Close a specific connection pool (or all pools if no key is given). */
332
+ closeSmtpPool(poolKey?: string): Promise<void>;
333
+ /** Get status of all SMTP client connection pools. */
334
+ getSmtpPoolStatus(): Promise<ISmtpPoolStatus>;
335
+ /**
336
+ * Start the Rust SMTP server.
337
+ * The server will listen on the configured ports and emit events for
338
+ * emailReceived and authRequest that must be handled by the caller.
339
+ */
340
+ startSmtpServer(config: ISmtpServerConfig): Promise<boolean>;
341
+ /** Stop the Rust SMTP server. */
342
+ stopSmtpServer(): Promise<void>;
343
+ /**
344
+ * Send the result of email processing back to the Rust SMTP server.
345
+ * This resolves a pending correlation-ID callback, allowing the Rust
346
+ * server to send the SMTP response to the client.
347
+ */
348
+ sendEmailProcessingResult(opts: {
349
+ correlationId: string;
350
+ accepted: boolean;
351
+ smtpCode?: number;
352
+ smtpMessage?: string;
353
+ }): Promise<void>;
354
+ /**
355
+ * Send the result of authentication validation back to the Rust SMTP server.
356
+ */
357
+ sendAuthResult(opts: {
358
+ correlationId: string;
359
+ success: boolean;
360
+ message?: string;
361
+ }): Promise<void>;
362
+ /**
363
+ * Send SCRAM credentials back to the Rust SMTP server.
364
+ * Values (salt, storedKey, serverKey) must be base64-encoded.
365
+ */
366
+ sendScramCredentialResult(opts: {
367
+ correlationId: string;
368
+ found: boolean;
369
+ salt?: string;
370
+ iterations?: number;
371
+ storedKey?: string;
372
+ serverKey?: string;
373
+ }): Promise<void>;
374
+ /** Update rate limit configuration at runtime. */
375
+ configureRateLimits(config: IRateLimitConfig): Promise<void>;
376
+ /**
377
+ * Register a handler for emailReceived events from the Rust SMTP server.
378
+ * These events fire when a complete email has been received and needs processing.
379
+ */
380
+ onEmailReceived(handler: (data: IEmailReceivedEvent) => void): void;
381
+ /**
382
+ * Register a handler for authRequest events from the Rust SMTP server.
383
+ * The handler must call sendAuthResult() with the correlationId.
384
+ */
385
+ onAuthRequest(handler: (data: IAuthRequestEvent) => void): void;
386
+ /**
387
+ * Register a handler for scramCredentialRequest events from the Rust SMTP server.
388
+ * The handler must call sendScramCredentialResult() with the correlationId.
389
+ */
390
+ onScramCredentialRequest(handler: (data: IScramCredentialRequestEvent) => void): void;
391
+ /** Remove an emailReceived event handler. */
392
+ offEmailReceived(handler: (data: IEmailReceivedEvent) => void): void;
393
+ /** Remove an authRequest event handler. */
394
+ offAuthRequest(handler: (data: IAuthRequestEvent) => void): void;
395
+ /** Remove a scramCredentialRequest event handler. */
396
+ offScramCredentialRequest(handler: (data: IScramCredentialRequestEvent) => void): void;
397
+ }
398
+ export type { IDkimVerificationResult, ISpfResult, IDmarcResult, IEmailSecurityResult, IValidationResult, IBounceDetection, IContentScanResult, IReputationResult as IRustReputationResult, IVersionInfo, ISmtpServerConfig, IRateLimitConfig, IEmailData, IEmailReceivedEvent, IAuthRequestEvent, IScramCredentialRequestEvent, IOutboundEmail, ISmtpSendResult, ISmtpSendOptions, ISmtpSendRawOptions, ISmtpVerifyOptions, ISmtpVerifyResult, ISmtpPoolStatus, };