nolimit-x 1.0.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.
@@ -0,0 +1,542 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+ const os = require('os');
4
+ const utils = require('./utils');
5
+ const placeholders = require('./placeholders');
6
+ const MessageEncryption = require('./encryption');
7
+ const MultiHandler = require('./multi-handler');
8
+ const AttachmentHandler = require('./attachment-handler');
9
+ const DocumentGenerator = require('./document-generator');
10
+ const QRGenerator = require('./qr-generator');
11
+ const Obfuscator = require('./obfuscator');
12
+ const pMap = require('p-map');
13
+
14
+ // Configuration management
15
+ class ConfigManager {
16
+ constructor(configPath = './config.json') {
17
+ this.configPath = configPath;
18
+ this.config = null;
19
+ this.smtpConfig = null;
20
+ this.emailList = [];
21
+ this.sendersList = [];
22
+ this.messageBody = '';
23
+ this.attachments = [];
24
+ this.faviconCache = {};
25
+ this.turbo = false;
26
+ this.concurrency = 2;
27
+
28
+ // Initialize new handlers
29
+ this.encryption = new MessageEncryption();
30
+ this.multiHandler = new MultiHandler();
31
+ this.attachmentHandler = new AttachmentHandler();
32
+
33
+ // Initialize Priority 2 handlers
34
+ this.documentGenerator = new DocumentGenerator();
35
+ this.qrGenerator = new QRGenerator();
36
+ this.obfuscator = new Obfuscator();
37
+ }
38
+
39
+ // Load configuration from file
40
+ loadConfig() {
41
+ try {
42
+ if (!fs.existsSync(this.configPath)) {
43
+ throw new Error(`Config file not found: ${this.configPath}`);
44
+ }
45
+
46
+ this.config = JSON.parse(fs.readFileSync(this.configPath, 'utf8'));
47
+ this.smtpConfig = this.config.smtp[0];
48
+
49
+ // Turbo mode logic
50
+ this.turbo = !!this.config.configurations?.system?.turbo;
51
+ this.concurrency = this.turbo ? Math.max(4, os.cpus().length) : 2;
52
+
53
+ console.log(`✓ Configuration loaded from ${this.configPath}`);
54
+ console.log(`✓ Turbo mode: ${this.turbo ? 'ON' : 'OFF'} (Concurrency: ${this.concurrency})`);
55
+ return true;
56
+ } catch (error) {
57
+ console.error(`✗ Failed to load config: ${error.message}`);
58
+ return false;
59
+ }
60
+ }
61
+
62
+ // Load email list
63
+ loadEmailList() {
64
+ try {
65
+ const emailPath = this.config.emails_list.path;
66
+ if (!fs.existsSync(emailPath)) {
67
+ throw new Error(`Email list file not found: ${emailPath}`);
68
+ }
69
+
70
+ const content = fs.readFileSync(emailPath, 'utf8');
71
+ this.emailList = content.split(os.EOL)
72
+ .filter(email => email.trim() && !email.startsWith('#') && utils.isValidEmail(email.trim()));
73
+
74
+ console.log(`✓ Loaded ${this.emailList.length} valid email addresses`);
75
+ return true;
76
+ } catch (error) {
77
+ console.error(`✗ Failed to load email list: ${error.message}`);
78
+ return false;
79
+ }
80
+ }
81
+
82
+ // Load senders list
83
+ loadSendersList() {
84
+ try {
85
+ const sendersPath = this.config.senders_list.path;
86
+ if (!fs.existsSync(sendersPath)) {
87
+ throw new Error(`Senders list file not found: ${sendersPath}`);
88
+ }
89
+
90
+ const content = fs.readFileSync(sendersPath, 'utf8');
91
+ this.sendersList = content.split(os.EOL)
92
+ .filter(sender => sender.trim() && !sender.startsWith('#') && utils.isValidEmail(sender.trim()));
93
+
94
+ console.log(`✓ Loaded ${this.sendersList.length} valid sender addresses`);
95
+
96
+ // Load into multi-handler for rotation
97
+ this.multiHandler.loadSenders(sendersPath);
98
+
99
+ return true;
100
+ } catch (error) {
101
+ console.error(`✗ Failed to load senders list: ${error.message}`);
102
+ return false;
103
+ }
104
+ }
105
+
106
+ // Load message body
107
+ loadMessageBody() {
108
+ try {
109
+ const messagePath = this.config.messages_body.path;
110
+ if (!fs.existsSync(messagePath)) {
111
+ throw new Error(`Message body file not found: ${messagePath}`);
112
+ }
113
+
114
+ this.messageBody = fs.readFileSync(messagePath, 'utf8');
115
+ console.log(`✓ Loaded message body from ${messagePath}`);
116
+
117
+ // Load additional multi-content if configured
118
+ this.loadMultiContent();
119
+
120
+ return true;
121
+ } catch (error) {
122
+ console.error(`✗ Failed to load message body: ${error.message}`);
123
+ return false;
124
+ }
125
+ }
126
+
127
+ // Load multiple content files
128
+ loadMultiContent() {
129
+ try {
130
+ // Load subjects if multiple subjects is enabled
131
+ if (this.config.configurations.agent.multiple_subjects && this.config.subjects_list) {
132
+ this.multiHandler.loadSubjects(this.config.subjects_list.path);
133
+ }
134
+
135
+ // Load from names if multiple from names is enabled
136
+ if (this.config.configurations.agent.multiple_from_names && this.config.froms_list) {
137
+ this.multiHandler.loadFromNames(this.config.froms_list.path);
138
+ }
139
+
140
+ // Load links if multiple links is enabled
141
+ if (this.config.configurations.agent.multiple_links && this.config.links_list) {
142
+ this.multiHandler.loadLinks(this.config.links_list.path);
143
+ }
144
+ } catch (error) {
145
+ console.warn(`Failed to load some multi-content: ${error.message}`);
146
+ }
147
+ }
148
+
149
+ // Load attachments
150
+ loadAttachments() {
151
+ try {
152
+ if (!this.config.configurations.use_attachment) {
153
+ console.log('✓ Attachments disabled in configuration');
154
+ return true;
155
+ }
156
+
157
+ this.attachments = [];
158
+ for (const attachment of this.config.attachments) {
159
+ if (attachment.active && fs.existsSync(attachment.path)) {
160
+ this.attachments.push({
161
+ filename: attachment.filename,
162
+ path: attachment.path,
163
+ active: attachment.active,
164
+ obfuscate: attachment.obfuscate || false,
165
+ encrypted: attachment.encrypted || false,
166
+ scripter: attachment.scripter || false
167
+ });
168
+ }
169
+ }
170
+
171
+ // Get attachment statistics
172
+ const stats = this.attachmentHandler.getAttachmentStats(this.config.attachments);
173
+ console.log(`✓ Loaded ${stats.active} active attachments (${stats.encrypted} encrypted, ${stats.obfuscated} obfuscated, ${stats.scripted} scripted)`);
174
+
175
+ return true;
176
+ } catch (error) {
177
+ console.error(`✗ Failed to load attachments: ${error.message}`);
178
+ return false;
179
+ }
180
+ }
181
+
182
+ // Get random sender
183
+ getRandomSender() {
184
+ // Use multi-handler if multiple senders is enabled
185
+ if (this.config.configurations.agent.multiple_senders) {
186
+ const sender = this.multiHandler.getRandomSender();
187
+ if (sender) return sender;
188
+ }
189
+
190
+ // Fallback to original method
191
+ if (this.sendersList.length === 0) {
192
+ return this.config.configurations.from_email;
193
+ }
194
+
195
+ const randomIndex = Math.floor(Math.random() * this.sendersList.length);
196
+ return this.sendersList[randomIndex];
197
+ }
198
+
199
+ // Get next sender (round-robin)
200
+ getNextSender() {
201
+ if (this.config.configurations.agent.multiple_senders) {
202
+ const sender = this.multiHandler.getNextSender();
203
+ if (sender) return sender;
204
+ }
205
+
206
+ return this.getRandomSender();
207
+ }
208
+
209
+ // Get subject
210
+ getSubject() {
211
+ if (this.config.configurations.agent.multiple_subjects) {
212
+ const subject = this.multiHandler.getRandomSubject();
213
+ if (subject) return subject;
214
+ }
215
+
216
+ return this.config.configurations.message.mail_subject;
217
+ }
218
+
219
+ // Get from name
220
+ getFromName() {
221
+ if (this.config.configurations.agent.multiple_from_names) {
222
+ const fromName = this.multiHandler.getRandomFromName();
223
+ if (fromName) return fromName;
224
+ }
225
+
226
+ return this.config.configurations.message.from_name;
227
+ }
228
+
229
+ // Priority 2: Document Generation
230
+ async generateDocument(htmlContent, format = 'pdf', options = {}) {
231
+ try {
232
+ switch (format.toLowerCase()) {
233
+ case 'pdf':
234
+ return await this.documentGenerator.htmlToPdf(htmlContent, options);
235
+ case 'docx':
236
+ case 'doc':
237
+ case 'rtf':
238
+ return await this.documentGenerator.htmlToDoc(htmlContent, format, options);
239
+ case 'epub':
240
+ return await this.documentGenerator.htmlToEpub(htmlContent, options);
241
+ case 'xlsx':
242
+ return await this.documentGenerator.htmlToXlsx(htmlContent);
243
+ case 'pptx':
244
+ return await this.documentGenerator.htmlToPptx(htmlContent, options);
245
+ default:
246
+ console.warn(`Unsupported document format: ${format}`);
247
+ return null;
248
+ }
249
+ } catch (error) {
250
+ console.error(`Document generation failed: ${error.message}`);
251
+ return null;
252
+ }
253
+ }
254
+
255
+ // Priority 2: QR Code Generation
256
+ async generateQRCode(data, purpose = 'general', options = {}) {
257
+ try {
258
+ return await this.qrGenerator.generateMultiPurposeQR(data, purpose, options);
259
+ } catch (error) {
260
+ console.error(`QR code generation failed: ${error.message}`);
261
+ return null;
262
+ }
263
+ }
264
+
265
+ // Priority 2: Embed QR code in message
266
+ embedQRInMessage(messageHtml, qrDataURL, position = 'bottom', size = 'medium') {
267
+ return this.qrGenerator.embedQRInMessage(messageHtml, qrDataURL, position, size);
268
+ }
269
+
270
+ // Priority 2: Obfuscation
271
+ obfuscateContent(content, method = 'base64', options = {}) {
272
+ try {
273
+ return this.obfuscator.obfuscate(content, method, options);
274
+ } catch (error) {
275
+ console.error(`Obfuscation failed: ${error.message}`);
276
+ return content; // Return original content if obfuscation fails
277
+ }
278
+ }
279
+
280
+ // Priority 2: Deobfuscation
281
+ deobfuscateContent(content, method = 'base64', options = {}) {
282
+ try {
283
+ return this.obfuscator.deobfuscate(content, method, options);
284
+ } catch (error) {
285
+ console.error(`Deobfuscation failed: ${error.message}`);
286
+ return content; // Return original content if deobfuscation fails
287
+ }
288
+ }
289
+
290
+ // Priority 2: Obfuscate URLs
291
+ obfuscateURL(url, method = 'base64') {
292
+ return this.obfuscator.obfuscateURL(url, method);
293
+ }
294
+
295
+ // Priority 2: Obfuscate JavaScript
296
+ obfuscateJavaScript(code, options = {}) {
297
+ return this.obfuscator.obfuscateJavaScript(code, options);
298
+ }
299
+
300
+ // Priority 2: Obfuscate HTML
301
+ obfuscateHTML(html, options = {}) {
302
+ return this.obfuscator.obfuscateHTML(html, options);
303
+ }
304
+
305
+ // Get configuration summary
306
+ getSummary() {
307
+ return {
308
+ smtp: {
309
+ host: this.smtpConfig?.host,
310
+ port: this.smtpConfig?.port,
311
+ secure: this.smtpConfig?.secure,
312
+ user: utils.maskEmail(this.smtpConfig?.user || '')
313
+ },
314
+ campaign: {
315
+ totalEmails: this.emailList.length,
316
+ totalSenders: this.sendersList.length,
317
+ attachments: this.attachments.length,
318
+ useAttachments: this.config.configurations.use_attachment,
319
+ multiThreading: this.config.configurations.agent.is_multi_thread,
320
+ threads: this.config.configurations.agent.how_many_thread,
321
+ delaySending: this.config.configurations.system.delay_sending,
322
+ delaySeconds: this.config.configurations.system.delay_sending_seconds
323
+ }
324
+ };
325
+ }
326
+
327
+ // Turbo parallel utility
328
+ async turboMap(items, fn) {
329
+ return await pMap(items, fn, { concurrency: this.concurrency });
330
+ }
331
+ }
332
+
333
+ // Campaign processor
334
+ class CampaignProcessor {
335
+ constructor(configManager) {
336
+ this.configManager = configManager;
337
+ this.processedEmails = 0;
338
+ this.successfulSends = 0;
339
+ this.failedSends = 0;
340
+ this.startTime = null;
341
+ this.endTime = null;
342
+ }
343
+
344
+ // Turbo mode: send campaign in parallel
345
+ async turboSendCampaign(sendEmailFn) {
346
+ const emails = this.configManager.emailList;
347
+ const turbo = this.configManager.turbo;
348
+ const concurrency = this.configManager.concurrency;
349
+ console.log(`\nTurbo mode is ON. Sending emails in parallel (concurrency: ${concurrency})...`);
350
+ await this.configManager.turboMap(emails, async (email, idx) => {
351
+ try {
352
+ const senderEmail = this.configManager.getNextSender();
353
+ const processed = await this.processEmail(email, senderEmail);
354
+ if (!processed) {
355
+ this.failedSends++;
356
+ return;
357
+ }
358
+ const result = await sendEmailFn(processed);
359
+ if (result === true) {
360
+ this.successfulSends++;
361
+ } else {
362
+ this.failedSends++;
363
+ }
364
+ } catch (err) {
365
+ this.failedSends++;
366
+ console.error(`Turbo send error for ${email}:`, err.message);
367
+ } finally {
368
+ this.processedEmails++;
369
+ }
370
+ });
371
+ }
372
+
373
+ // Standard mode: send campaign sequentially
374
+ async sequentialSendCampaign(sendEmailFn) {
375
+ const emails = this.configManager.emailList;
376
+ console.log(`\nTurbo mode is OFF. Sending emails sequentially...`);
377
+ for (const email of emails) {
378
+ try {
379
+ const senderEmail = this.configManager.getNextSender();
380
+ const processed = await this.processEmail(email, senderEmail);
381
+ if (!processed) {
382
+ this.failedSends++;
383
+ continue;
384
+ }
385
+ const result = await sendEmailFn(processed);
386
+ if (result === true) {
387
+ this.successfulSends++;
388
+ } else {
389
+ this.failedSends++;
390
+ }
391
+ } catch (err) {
392
+ this.failedSends++;
393
+ console.error(`Sequential send error for ${email}:`, err.message);
394
+ } finally {
395
+ this.processedEmails++;
396
+ }
397
+ }
398
+ }
399
+
400
+ // Main campaign entry point
401
+ async sendCampaign(sendEmailFn) {
402
+ this.startTimer();
403
+ if (this.configManager.turbo) {
404
+ await this.turboSendCampaign(sendEmailFn);
405
+ } else {
406
+ await this.sequentialSendCampaign(sendEmailFn);
407
+ }
408
+ this.endTimer();
409
+ }
410
+
411
+ // Initialize campaign
412
+ async initialize() {
413
+ console.log('\nInitializing campaign...');
414
+
415
+ if (!this.configManager.loadConfig()) return false;
416
+ if (!this.configManager.loadEmailList()) return false;
417
+ if (!this.configManager.loadSendersList()) return false;
418
+ if (!this.configManager.loadMessageBody()) return false;
419
+ if (!this.configManager.loadAttachments()) return false;
420
+
421
+ // Pre-fetch favicons for all domains to avoid delays during sending
422
+ console.log('\nPre-fetching favicons...');
423
+ const domains = [...new Set(this.configManager.emailList.map(email => utils.getDomainFromEmail(email)))];
424
+ await utils.batchFetchFavicons(domains);
425
+
426
+ const summary = this.configManager.getSummary();
427
+ console.log('\n📊 Campaign Summary:');
428
+ console.log(` SMTP: ${summary.smtp.host}:${summary.smtp.port}`);
429
+ console.log(` Targets: ${summary.campaign.totalEmails}`);
430
+ console.log(` Senders: ${summary.campaign.totalSenders}`);
431
+ console.log(` Attachments: ${summary.campaign.attachments}`);
432
+ console.log(` Multi-threading: ${summary.campaign.multiThreading ? 'Yes' : 'No'}`);
433
+ console.log(` Delay: ${summary.campaign.delaySending ? `${summary.campaign.delaySeconds}s` : 'No'}`);
434
+
435
+ return true;
436
+ }
437
+
438
+ // Process a single email
439
+ async processEmail(email, senderEmail) {
440
+ try {
441
+ // Replace placeholders in message body
442
+ const processedBody = await placeholders.replacePlaceholders(
443
+ this.configManager.messageBody,
444
+ email,
445
+ this.configManager.config.configurations.from_name,
446
+ senderEmail
447
+ );
448
+
449
+ // Replace placeholders in subject
450
+ const processedSubject = await placeholders.replacePlaceholders(
451
+ this.configManager.config.configurations.mail_subject,
452
+ email,
453
+ this.configManager.config.configurations.from_name,
454
+ senderEmail
455
+ );
456
+
457
+ // Process attachments if any
458
+ const processedAttachments = [];
459
+ if (this.configManager.config.configurations.use_attachment && this.configManager.attachments.length > 0) {
460
+ for (const attachment of this.configManager.attachments) {
461
+ try {
462
+ const attachmentContent = await utils.readContentFromFile(attachment.path);
463
+ const processedContent = await placeholders.replacePlaceholders(
464
+ attachmentContent,
465
+ email,
466
+ this.configManager.config.configurations.from_name,
467
+ senderEmail
468
+ );
469
+
470
+ const processedFilename = await placeholders.replacePlaceholders(
471
+ attachment.filename,
472
+ email,
473
+ this.configManager.config.configurations.from_name,
474
+ senderEmail
475
+ );
476
+
477
+ processedAttachments.push({
478
+ filename: processedFilename,
479
+ content: processedContent,
480
+ obfuscate: attachment.obfuscate,
481
+ encrypted: attachment.encrypted,
482
+ scripter: attachment.scripter
483
+ });
484
+ } catch (error) {
485
+ console.error(`Failed to process attachment ${attachment.filename}: ${error.message}`);
486
+ }
487
+ }
488
+ }
489
+
490
+ return {
491
+ email,
492
+ senderEmail,
493
+ subject: processedSubject,
494
+ body: processedBody,
495
+ attachments: processedAttachments,
496
+ fromName: this.configManager.config.configurations.from_name,
497
+ replyTo: this.configManager.config.configurations.reply_to,
498
+ priority: this.configManager.config.configurations.mail_priority
499
+ };
500
+
501
+ } catch (error) {
502
+ console.error(`Error processing email ${email}: ${error.message}`);
503
+ return null;
504
+ }
505
+ }
506
+
507
+ // Get campaign statistics
508
+ getStats() {
509
+ const duration = this.endTime ? this.endTime - this.startTime : 0;
510
+ const rate = duration > 0 ? (this.successfulSends / (duration / 1000)).toFixed(2) : 0;
511
+
512
+ return {
513
+ processed: this.processedEmails,
514
+ successful: this.successfulSends,
515
+ failed: this.failedSends,
516
+ total: this.configManager.emailList.length,
517
+ duration: duration,
518
+ rate: rate,
519
+ successRate: this.processedEmails > 0 ? ((this.successfulSends / this.processedEmails) * 100).toFixed(2) : 0
520
+ };
521
+ }
522
+
523
+ // Start campaign timer
524
+ startTimer() {
525
+ this.startTime = Date.now();
526
+ console.log(`\nCampaign started at ${new Date().toLocaleString()}`);
527
+ }
528
+
529
+ // End campaign timer
530
+ endTimer() {
531
+ this.endTime = Date.now();
532
+ const stats = this.getStats();
533
+ console.log(`\n🏁 Campaign completed in ${(stats.duration / 1000).toFixed(2)}s`);
534
+ console.log(` Success Rate: ${stats.successRate}%`);
535
+ console.log(` Rate: ${stats.rate} emails/second`);
536
+ }
537
+ }
538
+
539
+ module.exports = {
540
+ ConfigManager,
541
+ CampaignProcessor
542
+ };