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.
package/bin/nolimit ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+
3
+ require("../src/cli");
package/package.json ADDED
@@ -0,0 +1,18 @@
1
+ {
2
+ "name": "nolimit-x",
3
+ "version": "1.0.0",
4
+ "description": "Advanced email sender for red team operations",
5
+ "main": "src/cli.js",
6
+ "bin": {
7
+ "nolimit": "./src/cli.js"
8
+ },
9
+ "scripts": {
10
+ "test": "echo \"Error: no test specified\" && exit 1"
11
+ },
12
+ "keywords": ["email", "sender", "red-team", "smtp"],
13
+ "author": "",
14
+ "license": "ISC",
15
+ "dependencies": {
16
+ "commander": "^11.0.0"
17
+ }
18
+ }
@@ -0,0 +1,253 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+ const crypto = require('crypto');
4
+ const MessageEncryption = require('./encryption');
5
+
6
+ class AttachmentHandler {
7
+ constructor() {
8
+ this.encryption = new MessageEncryption();
9
+ }
10
+
11
+ // Process attachment based on configuration
12
+ async processAttachment(attachmentConfig, messageContent = '') {
13
+ try {
14
+ if (!attachmentConfig.active) {
15
+ return null;
16
+ }
17
+
18
+ let content = '';
19
+ let filename = attachmentConfig.filename;
20
+
21
+ // Read attachment content
22
+ if (fs.existsSync(attachmentConfig.path)) {
23
+ content = fs.readFileSync(attachmentConfig.path, 'utf8');
24
+ } else {
25
+ console.warn(`Attachment file not found: ${attachmentConfig.path}`);
26
+ return null;
27
+ }
28
+
29
+ // Process filename placeholders
30
+ filename = await this.processFilenamePlaceholders(filename);
31
+
32
+ // Apply obfuscation if enabled
33
+ if (attachmentConfig.obfuscate) {
34
+ content = this.obfuscateContent(content);
35
+ }
36
+
37
+ // Apply encryption if enabled
38
+ if (attachmentConfig.encrypted) {
39
+ const encryptedAttachment = this.encryption.createEncryptedAttachment(content, filename);
40
+ if (encryptedAttachment) {
41
+ return {
42
+ filename: encryptedAttachment.filename,
43
+ content: encryptedAttachment.content,
44
+ contentType: 'application/octet-stream',
45
+ encrypted: true,
46
+ metadata: encryptedAttachment.metadata
47
+ };
48
+ }
49
+ }
50
+
51
+ // Apply scripter if enabled
52
+ if (attachmentConfig.scripter) {
53
+ content = this.addScriptingCapabilities(content);
54
+ }
55
+
56
+ // Determine content type
57
+ const contentType = this.getContentType(filename);
58
+
59
+ return {
60
+ filename: filename,
61
+ content: content,
62
+ contentType: contentType,
63
+ encrypted: false
64
+ };
65
+
66
+ } catch (error) {
67
+ console.error(`Failed to process attachment ${attachmentConfig.filename}:`, error.message);
68
+ return null;
69
+ }
70
+ }
71
+
72
+ // Process filename placeholders
73
+ async processFilenamePlaceholders(filename) {
74
+ // Replace RANDOM_NUM placeholders
75
+ filename = filename.replace(/\[\[-RANDOM_NUM\((\d+)\)-\]\]/g, (match, digits) => {
76
+ const min = Math.pow(10, digits - 1);
77
+ const max = Math.pow(10, digits) - 1;
78
+ return Math.floor(Math.random() * (max - min + 1)) + min;
79
+ });
80
+
81
+ // Replace RANDOM_STR placeholders
82
+ filename = filename.replace(/\[\[-RANDOM_STR\((\d+),'([a-zA-Z]*)'\)-\]\]/g, (match, length, type) => {
83
+ return this.generateRandomString(parseInt(length), type);
84
+ });
85
+
86
+ return filename;
87
+ }
88
+
89
+ // Generate random string
90
+ generateRandomString(length, type = '') {
91
+ let characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
92
+
93
+ if (type === 'alpha') {
94
+ characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
95
+ } else if (type === 'numeric') {
96
+ characters = '0123456789';
97
+ } else if (type === 'uppercase') {
98
+ characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
99
+ } else if (type === 'lowercase') {
100
+ characters = 'abcdefghijklmnopqrstuvwxyz';
101
+ }
102
+
103
+ let result = '';
104
+ const charactersLength = characters.length;
105
+ for (let i = 0; i < length; i++) {
106
+ result += characters.charAt(Math.floor(Math.random() * charactersLength));
107
+ }
108
+ return result;
109
+ }
110
+
111
+ // Obfuscate content
112
+ obfuscateContent(content) {
113
+ // Simple obfuscation techniques
114
+ let obfuscated = content;
115
+
116
+ // Replace common words with similar looking characters
117
+ const obfuscationMap = {
118
+ 'a': '@',
119
+ 'e': '3',
120
+ 'i': '1',
121
+ 'o': '0',
122
+ 's': '$',
123
+ 't': '7'
124
+ };
125
+
126
+ // Apply character substitution
127
+ for (const [original, replacement] of Object.entries(obfuscationMap)) {
128
+ obfuscated = obfuscated.replace(new RegExp(original, 'gi'), replacement);
129
+ }
130
+
131
+ // Add random whitespace
132
+ obfuscated = obfuscated.replace(/\s+/g, ' ').trim();
133
+
134
+ return obfuscated;
135
+ }
136
+
137
+ // Add scripting capabilities
138
+ addScriptingCapabilities(content) {
139
+ // Add JavaScript execution capabilities
140
+ const scriptWrapper = `
141
+ <script>
142
+ // Auto-execute on load
143
+ (function() {
144
+ try {
145
+ // Add any custom scripting here
146
+ console.log('Script executed successfully');
147
+
148
+ // Example: Track opening
149
+ if (typeof window !== 'undefined') {
150
+ window.addEventListener('load', function() {
151
+ // Track that the attachment was opened
152
+ console.log('Attachment opened at:', new Date().toISOString());
153
+ });
154
+ }
155
+ } catch (error) {
156
+ console.error('Script execution failed:', error);
157
+ }
158
+ })();
159
+ </script>
160
+ ${content}`;
161
+
162
+ return scriptWrapper;
163
+ }
164
+
165
+ // Get content type based on file extension
166
+ getContentType(filename) {
167
+ const ext = path.extname(filename).toLowerCase();
168
+
169
+ const mimeTypes = {
170
+ '.html': 'text/html',
171
+ '.htm': 'text/html',
172
+ '.txt': 'text/plain',
173
+ '.pdf': 'application/pdf',
174
+ '.doc': 'application/msword',
175
+ '.docx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
176
+ '.rtf': 'application/rtf',
177
+ '.epub': 'application/epub+zip',
178
+ '.xlsx': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
179
+ '.pptx': 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
180
+ '.svg': 'image/svg+xml',
181
+ '.png': 'image/png',
182
+ '.jpg': 'image/jpeg',
183
+ '.jpeg': 'image/jpeg',
184
+ '.gif': 'image/gif',
185
+ '.zip': 'application/zip',
186
+ '.rar': 'application/x-rar-compressed',
187
+ '.7z': 'application/x-7z-compressed'
188
+ };
189
+
190
+ return mimeTypes[ext] || 'application/octet-stream';
191
+ }
192
+
193
+ // Create EML attachment
194
+ createEMLAttachment(fromEmail, toEmail, subject, messageContent, attachmentName = 'message.eml') {
195
+ const emlContent = `From: ${fromEmail}
196
+ To: ${toEmail}
197
+ Subject: ${subject}
198
+ Date: ${new Date().toUTCString()}
199
+ MIME-Version: 1.0
200
+ Content-Type: text/html; charset=UTF-8
201
+
202
+ ${messageContent}`;
203
+
204
+ return {
205
+ filename: attachmentName,
206
+ content: emlContent,
207
+ contentType: 'message/rfc822'
208
+ };
209
+ }
210
+
211
+ // Validate attachment configuration
212
+ validateAttachmentConfig(attachmentConfig) {
213
+ const requiredFields = ['filename', 'path', 'active'];
214
+
215
+ for (const field of requiredFields) {
216
+ if (!(field in attachmentConfig)) {
217
+ console.error(`Missing required field in attachment config: ${field}`);
218
+ return false;
219
+ }
220
+ }
221
+
222
+ if (attachmentConfig.active && !fs.existsSync(attachmentConfig.path)) {
223
+ console.warn(`Active attachment file not found: ${attachmentConfig.path}`);
224
+ return false;
225
+ }
226
+
227
+ return true;
228
+ }
229
+
230
+ // Get attachment statistics
231
+ getAttachmentStats(attachments) {
232
+ const stats = {
233
+ total: attachments.length,
234
+ active: 0,
235
+ encrypted: 0,
236
+ obfuscated: 0,
237
+ scripted: 0,
238
+ valid: 0
239
+ };
240
+
241
+ for (const attachment of attachments) {
242
+ if (attachment.active) stats.active++;
243
+ if (attachment.encrypted) stats.encrypted++;
244
+ if (attachment.obfuscate) stats.obfuscated++;
245
+ if (attachment.scripter) stats.scripted++;
246
+ if (this.validateAttachmentConfig(attachment)) stats.valid++;
247
+ }
248
+
249
+ return stats;
250
+ }
251
+ }
252
+
253
+ module.exports = AttachmentHandler;
package/src/cli.js ADDED
@@ -0,0 +1,31 @@
1
+ #!/usr/bin/env node
2
+ const { Command } = require("commander");
3
+ const init = require("./init");
4
+ const { send } = require("./sender");
5
+
6
+ const program = new Command();
7
+
8
+ program
9
+ .name("nolimit")
10
+ .version("1.0.0")
11
+ .description("Advanced email sender for red team operations");
12
+
13
+ program
14
+ .command("init")
15
+ .argument("<projectName>", "Name of the project to create")
16
+ .description("Initialize a new email campaign project")
17
+ .action((projectName) => {
18
+ console.log("Init command called with:", projectName);
19
+ init(projectName);
20
+ });
21
+
22
+ program
23
+ .command("send")
24
+ .description("Send emails using current configuration")
25
+ .option("-c, --config <path>", "Config file path", "templates/config.json")
26
+ .action((options) => {
27
+ console.log("Send command called with options:", options);
28
+ send(options);
29
+ });
30
+
31
+ program.parse();
@@ -0,0 +1,275 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+ const puppeteer = require('puppeteer');
4
+ const { execSync } = require('child_process');
5
+
6
+ class DocumentGenerator {
7
+ constructor() {
8
+ this.browser = null;
9
+ }
10
+
11
+ // Initialize browser for PDF generation
12
+ async initBrowser() {
13
+ if (!this.browser) {
14
+ this.browser = await puppeteer.launch({
15
+ headless: true,
16
+ args: ['--no-sandbox', '--disable-setuid-sandbox']
17
+ });
18
+ }
19
+ return this.browser;
20
+ }
21
+
22
+ // Close browser
23
+ async closeBrowser() {
24
+ if (this.browser) {
25
+ await this.browser.close();
26
+ this.browser = null;
27
+ }
28
+ }
29
+
30
+ // Convert HTML to PDF
31
+ async htmlToPdf(htmlContent, options = {}) {
32
+ try {
33
+ const browser = await this.initBrowser();
34
+ const page = await browser.newPage();
35
+
36
+ // Set content
37
+ await page.setContent(htmlContent, { waitUntil: 'networkidle0' });
38
+
39
+ // PDF options
40
+ const pdfOptions = {
41
+ format: options.format || 'A4',
42
+ printBackground: true,
43
+ margin: {
44
+ top: options.marginTop || '1cm',
45
+ right: options.marginRight || '1cm',
46
+ bottom: options.marginBottom || '1cm',
47
+ left: options.marginLeft || '1cm'
48
+ },
49
+ ...options
50
+ };
51
+
52
+ const pdfBuffer = await page.pdf(pdfOptions);
53
+ await page.close();
54
+
55
+ return pdfBuffer;
56
+ } catch (error) {
57
+ console.error('PDF generation failed:', error.message);
58
+ return null;
59
+ }
60
+ }
61
+
62
+ // Convert HTML to DOC/DOCX using pandoc
63
+ async htmlToDoc(htmlContent, format = 'docx', options = {}) {
64
+ try {
65
+ // Create temporary HTML file
66
+ const tempHtmlPath = path.join(process.cwd(), 'temp_message.html');
67
+ fs.writeFileSync(tempHtmlPath, htmlContent);
68
+
69
+ // Create output filename
70
+ const outputPath = path.join(process.cwd(), `temp_output.${format}`);
71
+
72
+ // Build pandoc command
73
+ let command = `pandoc "${tempHtmlPath}" -o "${outputPath}"`;
74
+
75
+ // Add format-specific options
76
+ if (format === 'docx') {
77
+ command += ' --reference-doc=template.docx' // if template exists
78
+ } else if (format === 'rtf') {
79
+ command += ' --standalone'
80
+ }
81
+
82
+ // Execute pandoc
83
+ execSync(command, { stdio: 'pipe' });
84
+
85
+ // Read the generated file
86
+ const docBuffer = fs.readFileSync(outputPath);
87
+
88
+ // Cleanup temporary files
89
+ fs.unlinkSync(tempHtmlPath);
90
+ fs.unlinkSync(outputPath);
91
+
92
+ return docBuffer;
93
+ } catch (error) {
94
+ console.error(`${format.toUpperCase()} generation failed:`, error.message);
95
+ return null;
96
+ }
97
+ }
98
+
99
+ // Convert HTML to EPUB
100
+ async htmlToEpub(htmlContent, metadata = {}) {
101
+ try {
102
+ // Create EPUB structure
103
+ const epubContent = this.createEpubStructure(htmlContent, metadata);
104
+
105
+ // For now, return a simple EPUB-like structure
106
+ // In a full implementation, you'd use a proper EPUB library
107
+ return Buffer.from(epubContent, 'utf8');
108
+ } catch (error) {
109
+ console.error('EPUB generation failed:', error.message);
110
+ return null;
111
+ }
112
+ }
113
+
114
+ // Create EPUB structure
115
+ createEpubStructure(htmlContent, metadata) {
116
+ const title = metadata.title || 'Document';
117
+ const author = metadata.author || 'NoLimit';
118
+ const publisher = metadata.publisher || 'HTML to EPUB Converter';
119
+
120
+ return `<?xml version="1.0" encoding="UTF-8"?>
121
+ <package xmlns="http://www.idpf.org/2007/opf" version="3.0" unique-identifier="uid">
122
+ <metadata xmlns:dc="http://purl.org/dc/elements/1.1/">
123
+ <dc:title>${title}</dc:title>
124
+ <dc:creator>${author}</dc:creator>
125
+ <dc:publisher>${publisher}</dc:publisher>
126
+ <dc:language>en</dc:language>
127
+ <dc:identifier id="uid">urn:uuid:${this.generateUUID()}</dc:identifier>
128
+ </metadata>
129
+ <manifest>
130
+ <item id="nav" href="nav.xhtml" media-type="application/xhtml+xml" properties="nav"/>
131
+ <item id="content" href="content.xhtml" media-type="application/xhtml+xml"/>
132
+ </manifest>
133
+ <spine>
134
+ <itemref idref="nav"/>
135
+ <itemref idref="content"/>
136
+ </spine>
137
+ </package>
138
+
139
+ <!-- content.xhtml -->
140
+ <?xml version="1.0" encoding="UTF-8"?>
141
+ <html xmlns="http://www.w3.org/1999/xhtml">
142
+ <head>
143
+ <title>${title}</title>
144
+ </head>
145
+ <body>
146
+ ${htmlContent}
147
+ </body>
148
+ </html>`;
149
+ }
150
+
151
+ // Convert HTML to XLSX (simple table extraction)
152
+ async htmlToXlsx(htmlContent) {
153
+ try {
154
+ // Extract tables from HTML and convert to XLSX format
155
+ // This is a simplified implementation
156
+ const xlsxContent = this.extractTablesToXlsx(htmlContent);
157
+ return Buffer.from(xlsxContent, 'utf8');
158
+ } catch (error) {
159
+ console.error('XLSX generation failed:', error.message);
160
+ return null;
161
+ }
162
+ }
163
+
164
+ // Extract tables from HTML
165
+ extractTablesToXlsx(htmlContent) {
166
+ // Simple table extraction - in a real implementation, you'd use a proper library
167
+ const tableRegex = /<table[^>]*>([\s\S]*?)<\/table>/gi;
168
+ const tables = [];
169
+ let match;
170
+
171
+ while ((match = tableRegex.exec(htmlContent)) !== null) {
172
+ tables.push(match[1]);
173
+ }
174
+
175
+ // Convert to CSV-like format (simplified XLSX)
176
+ let xlsxContent = '<?xml version="1.0" encoding="UTF-8"?>\n';
177
+ xlsxContent += '<workbook xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">\n';
178
+ xlsxContent += '<sheets>\n';
179
+ xlsxContent += '<sheet name="Sheet1" sheetId="1" r:id="rId1"/>\n';
180
+ xlsxContent += '</sheets>\n';
181
+ xlsxContent += '</workbook>\n';
182
+
183
+ return xlsxContent;
184
+ }
185
+
186
+ // Convert HTML to PPTX (simple slide generation)
187
+ async htmlToPptx(htmlContent, metadata = {}) {
188
+ try {
189
+ const title = metadata.title || 'Document';
190
+ const author = metadata.author || 'NoLimit';
191
+
192
+ // Create simple PPTX structure
193
+ const pptxContent = this.createPptxStructure(htmlContent, title, author);
194
+ return Buffer.from(pptxContent, 'utf8');
195
+ } catch (error) {
196
+ console.error('PPTX generation failed:', error.message);
197
+ return null;
198
+ }
199
+ }
200
+
201
+ // Create PPTX structure
202
+ createPptxStructure(htmlContent, title, author) {
203
+ return `<?xml version="1.0" encoding="UTF-8"?>
204
+ <p:presentation xmlns:p="http://schemas.openxmlformats.org/presentationml/2006/main">
205
+ <p:sldMasters>
206
+ <p:sldMaster>
207
+ <p:cSld>
208
+ <p:spTree>
209
+ <p:sp>
210
+ <p:txBody>
211
+ <a:p>
212
+ <a:r>
213
+ <a:t>${title}</a:t>
214
+ </a:r>
215
+ </a:p>
216
+ </p:txBody>
217
+ </p:sp>
218
+ </p:spTree>
219
+ </p:cSld>
220
+ </p:sldMaster>
221
+ </p:sldMasters>
222
+ <p:sldIdLst>
223
+ <p:sld>
224
+ <p:cSld>
225
+ <p:spTree>
226
+ <p:sp>
227
+ <p:txBody>
228
+ <a:p>
229
+ <a:r>
230
+ <a:t>${htmlContent.replace(/<[^>]*>/g, '')}</a:t>
231
+ </a:r>
232
+ </a:p>
233
+ </p:txBody>
234
+ </p:sp>
235
+ </p:spTree>
236
+ </p:cSld>
237
+ </p:sld>
238
+ </p:sldIdLst>
239
+ </p:presentation>`;
240
+ }
241
+
242
+ // Generate UUID for EPUB
243
+ generateUUID() {
244
+ return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
245
+ const r = Math.random() * 16 | 0;
246
+ const v = c === 'x' ? r : (r & 0x3 | 0x8);
247
+ return v.toString(16);
248
+ });
249
+ }
250
+
251
+ // Check if pandoc is available
252
+ isPandocAvailable() {
253
+ try {
254
+ execSync('pandoc --version', { stdio: 'pipe' });
255
+ return true;
256
+ } catch (error) {
257
+ return false;
258
+ }
259
+ }
260
+
261
+ // Get supported formats
262
+ getSupportedFormats() {
263
+ const formats = ['pdf'];
264
+
265
+ if (this.isPandocAvailable()) {
266
+ formats.push('docx', 'doc', 'rtf');
267
+ }
268
+
269
+ formats.push('epub', 'xlsx', 'pptx');
270
+
271
+ return formats;
272
+ }
273
+ }
274
+
275
+ module.exports = DocumentGenerator;