@push.rocks/smartmta 5.1.3 → 5.2.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.
- package/changelog.md +15 -0
- package/dist_ts/00_commitinfo_data.d.ts +8 -0
- package/dist_ts/00_commitinfo_data.js +9 -0
- package/dist_ts/index.d.ts +3 -0
- package/dist_ts/index.js +4 -0
- package/dist_ts/logger.d.ts +17 -0
- package/dist_ts/logger.js +76 -0
- package/dist_ts/mail/core/classes.bouncemanager.d.ts +185 -0
- package/dist_ts/mail/core/classes.bouncemanager.js +569 -0
- package/dist_ts/mail/core/classes.email.d.ts +291 -0
- package/dist_ts/mail/core/classes.email.js +802 -0
- package/dist_ts/mail/core/classes.emailvalidator.d.ts +61 -0
- package/dist_ts/mail/core/classes.emailvalidator.js +184 -0
- package/dist_ts/mail/core/classes.templatemanager.d.ts +95 -0
- package/dist_ts/mail/core/classes.templatemanager.js +240 -0
- package/dist_ts/mail/core/index.d.ts +4 -0
- package/dist_ts/mail/core/index.js +6 -0
- package/dist_ts/mail/delivery/classes.delivery.queue.d.ts +163 -0
- package/dist_ts/mail/delivery/classes.delivery.queue.js +488 -0
- package/dist_ts/mail/delivery/classes.delivery.system.d.ts +160 -0
- package/dist_ts/mail/delivery/classes.delivery.system.js +630 -0
- package/dist_ts/mail/delivery/classes.unified.rate.limiter.d.ts +200 -0
- package/dist_ts/mail/delivery/classes.unified.rate.limiter.js +820 -0
- package/dist_ts/mail/delivery/index.d.ts +4 -0
- package/dist_ts/mail/delivery/index.js +6 -0
- package/dist_ts/mail/delivery/interfaces.d.ts +140 -0
- package/dist_ts/mail/delivery/interfaces.js +17 -0
- package/dist_ts/mail/index.d.ts +7 -0
- package/dist_ts/mail/index.js +12 -0
- package/dist_ts/mail/routing/classes.dkim.manager.d.ts +25 -0
- package/dist_ts/mail/routing/classes.dkim.manager.js +127 -0
- package/dist_ts/mail/routing/classes.dns.manager.d.ts +79 -0
- package/dist_ts/mail/routing/classes.dns.manager.js +415 -0
- package/dist_ts/mail/routing/classes.domain.registry.d.ts +54 -0
- package/dist_ts/mail/routing/classes.domain.registry.js +119 -0
- package/dist_ts/mail/routing/classes.email.action.executor.d.ts +33 -0
- package/dist_ts/mail/routing/classes.email.action.executor.js +137 -0
- package/dist_ts/mail/routing/classes.email.router.d.ts +171 -0
- package/dist_ts/mail/routing/classes.email.router.js +494 -0
- package/dist_ts/mail/routing/classes.unified.email.server.d.ts +241 -0
- package/dist_ts/mail/routing/classes.unified.email.server.js +935 -0
- package/dist_ts/mail/routing/index.d.ts +7 -0
- package/dist_ts/mail/routing/index.js +9 -0
- package/dist_ts/mail/routing/interfaces.d.ts +187 -0
- package/dist_ts/mail/routing/interfaces.js +2 -0
- package/dist_ts/mail/security/classes.dkimcreator.d.ts +72 -0
- package/dist_ts/mail/security/classes.dkimcreator.js +360 -0
- package/dist_ts/mail/security/classes.spfverifier.d.ts +62 -0
- package/dist_ts/mail/security/classes.spfverifier.js +87 -0
- package/dist_ts/mail/security/index.d.ts +2 -0
- package/dist_ts/mail/security/index.js +4 -0
- package/dist_ts/paths.d.ts +14 -0
- package/dist_ts/paths.js +39 -0
- package/dist_ts/plugins.d.ts +24 -0
- package/dist_ts/plugins.js +28 -0
- package/dist_ts/security/classes.contentscanner.d.ts +130 -0
- package/dist_ts/security/classes.contentscanner.js +338 -0
- package/dist_ts/security/classes.ipreputationchecker.d.ts +73 -0
- package/dist_ts/security/classes.ipreputationchecker.js +263 -0
- package/dist_ts/security/classes.rustsecuritybridge.d.ts +403 -0
- package/dist_ts/security/classes.rustsecuritybridge.js +502 -0
- package/dist_ts/security/classes.securitylogger.d.ts +140 -0
- package/dist_ts/security/classes.securitylogger.js +235 -0
- package/dist_ts/security/index.d.ts +4 -0
- package/dist_ts/security/index.js +5 -0
- package/package.json +6 -1
- package/ts/00_commitinfo_data.ts +8 -0
- package/ts/index.ts +3 -0
- package/ts/logger.ts +91 -0
- package/ts/mail/core/classes.bouncemanager.ts +731 -0
- package/ts/mail/core/classes.email.ts +942 -0
- package/ts/mail/core/classes.emailvalidator.ts +239 -0
- package/ts/mail/core/classes.templatemanager.ts +320 -0
- package/ts/mail/core/index.ts +5 -0
- package/ts/mail/delivery/classes.delivery.queue.ts +645 -0
- package/ts/mail/delivery/classes.delivery.system.ts +816 -0
- package/ts/mail/delivery/classes.unified.rate.limiter.ts +1053 -0
- package/ts/mail/delivery/index.ts +5 -0
- package/ts/mail/delivery/interfaces.ts +167 -0
- package/ts/mail/index.ts +17 -0
- package/ts/mail/routing/classes.dkim.manager.ts +157 -0
- package/ts/mail/routing/classes.dns.manager.ts +573 -0
- package/ts/mail/routing/classes.domain.registry.ts +139 -0
- package/ts/mail/routing/classes.email.action.executor.ts +175 -0
- package/ts/mail/routing/classes.email.router.ts +575 -0
- package/ts/mail/routing/classes.unified.email.server.ts +1207 -0
- package/ts/mail/routing/index.ts +9 -0
- package/ts/mail/routing/interfaces.ts +202 -0
- package/ts/mail/security/classes.dkimcreator.ts +447 -0
- package/ts/mail/security/classes.spfverifier.ts +126 -0
- package/ts/mail/security/index.ts +3 -0
- package/ts/paths.ts +48 -0
- package/ts/plugins.ts +53 -0
- package/ts/security/classes.contentscanner.ts +400 -0
- package/ts/security/classes.ipreputationchecker.ts +315 -0
- package/ts/security/classes.rustsecuritybridge.ts +964 -0
- package/ts/security/classes.securitylogger.ts +299 -0
- 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,403 @@
|
|
|
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
|
+
/**
|
|
240
|
+
* Map Node.js process.platform / process.arch to the tsrust-style suffix
|
|
241
|
+
* used for cross-compiled binaries, e.g. mailer-bin_linux_amd64.
|
|
242
|
+
*/
|
|
243
|
+
private static getPlatformSuffix;
|
|
244
|
+
private constructor();
|
|
245
|
+
/** Get or create the singleton instance. */
|
|
246
|
+
static getInstance(): RustSecurityBridge;
|
|
247
|
+
/** Reset the singleton instance (for testing). */
|
|
248
|
+
static resetInstance(): void;
|
|
249
|
+
/** Configure resilience parameters. Can be called before or after getInstance(). */
|
|
250
|
+
static configure(config: Partial<IBridgeResilienceConfig>): void;
|
|
251
|
+
/** Current bridge state. */
|
|
252
|
+
get state(): BridgeState;
|
|
253
|
+
/** Whether the Rust process is currently running and accepting commands. */
|
|
254
|
+
get running(): boolean;
|
|
255
|
+
private setState;
|
|
256
|
+
/**
|
|
257
|
+
* Throws a descriptive error if the bridge is not in Running state.
|
|
258
|
+
* Called at the top of every command method.
|
|
259
|
+
*/
|
|
260
|
+
private ensureRunning;
|
|
261
|
+
/**
|
|
262
|
+
* Spawn the Rust binary and wait for the ready signal.
|
|
263
|
+
* @returns `true` if the binary started successfully, `false` otherwise.
|
|
264
|
+
*/
|
|
265
|
+
start(): Promise<boolean>;
|
|
266
|
+
/** Kill the Rust process deliberately. */
|
|
267
|
+
stop(): Promise<void>;
|
|
268
|
+
private attemptRestart;
|
|
269
|
+
/**
|
|
270
|
+
* Restore state after a successful restart:
|
|
271
|
+
* - Re-send startSmtpServer command if the SMTP server was running
|
|
272
|
+
*/
|
|
273
|
+
private restoreAfterRestart;
|
|
274
|
+
private startHealthCheck;
|
|
275
|
+
private stopHealthCheck;
|
|
276
|
+
/** Ping the Rust process. */
|
|
277
|
+
ping(): Promise<boolean>;
|
|
278
|
+
/** Get version information for all Rust crates. */
|
|
279
|
+
getVersion(): Promise<IVersionInfo>;
|
|
280
|
+
/** Validate an email address. */
|
|
281
|
+
validateEmail(email: string): Promise<IValidationResult>;
|
|
282
|
+
/** Detect bounce type from SMTP response / diagnostic code. */
|
|
283
|
+
detectBounce(opts: {
|
|
284
|
+
smtpResponse?: string;
|
|
285
|
+
diagnosticCode?: string;
|
|
286
|
+
statusCode?: string;
|
|
287
|
+
}): Promise<IBounceDetection>;
|
|
288
|
+
/** Scan email content for threats (phishing, spam, malware, etc.). */
|
|
289
|
+
scanContent(opts: {
|
|
290
|
+
subject?: string;
|
|
291
|
+
textBody?: string;
|
|
292
|
+
htmlBody?: string;
|
|
293
|
+
attachmentNames?: string[];
|
|
294
|
+
}): Promise<IContentScanResult>;
|
|
295
|
+
/** Check IP reputation via DNSBL. */
|
|
296
|
+
checkIpReputation(ip: string): Promise<IReputationResult>;
|
|
297
|
+
/** Verify DKIM signatures on a raw email message. */
|
|
298
|
+
verifyDkim(rawMessage: string): Promise<IDkimVerificationResult[]>;
|
|
299
|
+
/** Sign an email with DKIM (RSA or Ed25519). */
|
|
300
|
+
signDkim(opts: {
|
|
301
|
+
rawMessage: string;
|
|
302
|
+
domain: string;
|
|
303
|
+
selector?: string;
|
|
304
|
+
privateKey: string;
|
|
305
|
+
keyType?: string;
|
|
306
|
+
}): Promise<{
|
|
307
|
+
header: string;
|
|
308
|
+
signedMessage: string;
|
|
309
|
+
}>;
|
|
310
|
+
/** Check SPF for a sender. */
|
|
311
|
+
checkSpf(opts: {
|
|
312
|
+
ip: string;
|
|
313
|
+
heloDomain: string;
|
|
314
|
+
hostname?: string;
|
|
315
|
+
mailFrom: string;
|
|
316
|
+
}): Promise<ISpfResult>;
|
|
317
|
+
/**
|
|
318
|
+
* Compound email security verification: DKIM + SPF + DMARC in one IPC call.
|
|
319
|
+
*
|
|
320
|
+
* This is the preferred method for inbound email verification — it avoids
|
|
321
|
+
* 3 sequential round-trips and correctly passes raw mail-auth types internally.
|
|
322
|
+
*/
|
|
323
|
+
verifyEmail(opts: {
|
|
324
|
+
rawMessage: string;
|
|
325
|
+
ip: string;
|
|
326
|
+
heloDomain: string;
|
|
327
|
+
hostname?: string;
|
|
328
|
+
mailFrom: string;
|
|
329
|
+
}): Promise<IEmailSecurityResult>;
|
|
330
|
+
/** Send a structured email via the Rust SMTP client. */
|
|
331
|
+
sendOutboundEmail(opts: ISmtpSendOptions): Promise<ISmtpSendResult>;
|
|
332
|
+
/** Send a pre-formatted raw email via the Rust SMTP client. */
|
|
333
|
+
sendRawEmail(opts: ISmtpSendRawOptions): Promise<ISmtpSendResult>;
|
|
334
|
+
/** Verify connectivity to an SMTP server. */
|
|
335
|
+
verifySmtpConnection(opts: ISmtpVerifyOptions): Promise<ISmtpVerifyResult>;
|
|
336
|
+
/** Close a specific connection pool (or all pools if no key is given). */
|
|
337
|
+
closeSmtpPool(poolKey?: string): Promise<void>;
|
|
338
|
+
/** Get status of all SMTP client connection pools. */
|
|
339
|
+
getSmtpPoolStatus(): Promise<ISmtpPoolStatus>;
|
|
340
|
+
/**
|
|
341
|
+
* Start the Rust SMTP server.
|
|
342
|
+
* The server will listen on the configured ports and emit events for
|
|
343
|
+
* emailReceived and authRequest that must be handled by the caller.
|
|
344
|
+
*/
|
|
345
|
+
startSmtpServer(config: ISmtpServerConfig): Promise<boolean>;
|
|
346
|
+
/** Stop the Rust SMTP server. */
|
|
347
|
+
stopSmtpServer(): Promise<void>;
|
|
348
|
+
/**
|
|
349
|
+
* Send the result of email processing back to the Rust SMTP server.
|
|
350
|
+
* This resolves a pending correlation-ID callback, allowing the Rust
|
|
351
|
+
* server to send the SMTP response to the client.
|
|
352
|
+
*/
|
|
353
|
+
sendEmailProcessingResult(opts: {
|
|
354
|
+
correlationId: string;
|
|
355
|
+
accepted: boolean;
|
|
356
|
+
smtpCode?: number;
|
|
357
|
+
smtpMessage?: string;
|
|
358
|
+
}): Promise<void>;
|
|
359
|
+
/**
|
|
360
|
+
* Send the result of authentication validation back to the Rust SMTP server.
|
|
361
|
+
*/
|
|
362
|
+
sendAuthResult(opts: {
|
|
363
|
+
correlationId: string;
|
|
364
|
+
success: boolean;
|
|
365
|
+
message?: string;
|
|
366
|
+
}): Promise<void>;
|
|
367
|
+
/**
|
|
368
|
+
* Send SCRAM credentials back to the Rust SMTP server.
|
|
369
|
+
* Values (salt, storedKey, serverKey) must be base64-encoded.
|
|
370
|
+
*/
|
|
371
|
+
sendScramCredentialResult(opts: {
|
|
372
|
+
correlationId: string;
|
|
373
|
+
found: boolean;
|
|
374
|
+
salt?: string;
|
|
375
|
+
iterations?: number;
|
|
376
|
+
storedKey?: string;
|
|
377
|
+
serverKey?: string;
|
|
378
|
+
}): Promise<void>;
|
|
379
|
+
/** Update rate limit configuration at runtime. */
|
|
380
|
+
configureRateLimits(config: IRateLimitConfig): Promise<void>;
|
|
381
|
+
/**
|
|
382
|
+
* Register a handler for emailReceived events from the Rust SMTP server.
|
|
383
|
+
* These events fire when a complete email has been received and needs processing.
|
|
384
|
+
*/
|
|
385
|
+
onEmailReceived(handler: (data: IEmailReceivedEvent) => void): void;
|
|
386
|
+
/**
|
|
387
|
+
* Register a handler for authRequest events from the Rust SMTP server.
|
|
388
|
+
* The handler must call sendAuthResult() with the correlationId.
|
|
389
|
+
*/
|
|
390
|
+
onAuthRequest(handler: (data: IAuthRequestEvent) => void): void;
|
|
391
|
+
/**
|
|
392
|
+
* Register a handler for scramCredentialRequest events from the Rust SMTP server.
|
|
393
|
+
* The handler must call sendScramCredentialResult() with the correlationId.
|
|
394
|
+
*/
|
|
395
|
+
onScramCredentialRequest(handler: (data: IScramCredentialRequestEvent) => void): void;
|
|
396
|
+
/** Remove an emailReceived event handler. */
|
|
397
|
+
offEmailReceived(handler: (data: IEmailReceivedEvent) => void): void;
|
|
398
|
+
/** Remove an authRequest event handler. */
|
|
399
|
+
offAuthRequest(handler: (data: IAuthRequestEvent) => void): void;
|
|
400
|
+
/** Remove a scramCredentialRequest event handler. */
|
|
401
|
+
offScramCredentialRequest(handler: (data: IScramCredentialRequestEvent) => void): void;
|
|
402
|
+
}
|
|
403
|
+
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, };
|