• XSS.stack #1 – первый литературный журнал от юзеров форума

SMTP Спамер с уникализацией текста [SRC]

Кодер

WebDev
Забанен
Регистрация
26.10.2022
Сообщения
360
Реакции
272
Гарант сделки
14
Депозит
1.5004 Ł и др.
Пожалуйста, обратите внимание, что пользователь заблокирован
1741055506760.png

Простой SMTP Спаммер с веб панелью и уникализацией текста через API ChatGPT, ну и само собой с использованием прокси
Ну а также для удобства отслеживания: отстук статуса процессов в телегу

Данный продукт был написан давненько и никем не реализован, поэтому оставляю тут)

Используется Node.js (да здравствуй хардкод)

.env:
Код:
USERS=
TELEGRAM_BOT_TOKEN=
TELEGRAM_CHAT_ID=


main.js:
JavaScript:
const express = require('express');
const http = require('http');            
const { Server } = require('socket.io');
const bodyParser = require('body-parser');
const nodemailer = require('nodemailer');
const imapClient = require('imap-simple');
const fs = require('fs');
const path = require('path');
const multer = require('multer');
const dotenv = require('dotenv');
const session = require('express-session');
const { Configuration, OpenAIApi } = require('openai');
const axios = require('axios');
const { HttpsProxyAgent } = require('https-proxy-agent');

const app = express();
dotenv.config();

const PORT = 3000;

const server = http.createServer(app);
const io = new Server(server, {
    cors: {
        origin: "*"
    }
});

let subjects = [];
let proxies = [];
async function uniquifyText(text) {
    const API_KEY = '';
    const API_URL = 'https://api.openai.com/v1/chat/completions';

    const payload = {
        model: 'gpt-3.5-turbo',
        messages: [
            {
                role: 'system',
                content: 'Вы помощник, который делает текст уникальным.'
            },
            {
                role: 'user',
                content: `Перепиши следующий текст полностью своими словами, сохраняя общий смысл, но делая его уникальным и подходящим для новой аудитории. Избегай точного копирования структуры предложений и используемых формулировок. Постарайся сделать текст лаконичным, но при этом информативным. Убедись, что итоговый текст будет легким для восприятия и грамматически правильным. Используй только английский язык:\n${text}`
            }
        ],
        max_tokens: 500,
        temperature: 0.7,
    };

    const headers = {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${API_KEY}`,
    };

    try {
        console.log('Sending request to OpenAI API...');
        const response = await axios.post(API_URL, payload, { headers });
        console.log('OpenAI API response:', JSON.stringify(response.data, null, 2));

        if (
            response.data &&
            response.data.choices &&
            response.data.choices[0] &&
            response.data.choices[0].message &&
            response.data.choices[0].message.content
        ) {
            return response.data.choices[0].message.content.trim();
        } else {
            throw new Error('Response does not contain valid content.');
        }
    } catch (error) {
        const errorMessage = error.response ? JSON.stringify(error.response.data, null, 2) : error.message;
        console.error('Error with OpenAI API:', errorMessage);
        throw new Error(`Failed to uniquify text: ${errorMessage}`);
    }
}

const upload = multer({ dest: 'uploads/' });

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));

app.use(session({
    secret: 'secret-key',
    resave: false,
    saveUninitialized: true
}));

function isAuthenticated(req, res, next) {
    if (req.session && req.session.loggedIn) {
        return next();
    } else {
        res.redirect('/login');
    }
}

const users = process.env.USERS ? process.env.USERS.split(',').map(user => {
    const [username, password] = user.split(':');
    return { username, password };
}) : [];

app.get('/login', (req, res) => {
    res.send(`<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Login</title>
    <style>
        body {
            background-color: #1e1e1e;
            color: #c0c0c0;
            font-family: "Courier New", Courier, monospace;
            display: flex;
            justify-content: center;
            align-items: center;
            height: 100vh;
            margin: 0;
        }
        form {
            background-color: #2a2a2a;
            border: 1px solid #ff4040;
            border-radius: 8px;
            padding: 20px;
            text-align: center;
            width: 300px;
        }
        input, button {
            width: calc(100% - 20px);
            margin: 10px 0;
            padding: 10px;
            background-color: #3a3a3a;
            border: 1px solid #ff4040;
            color: #c0c0c0;
            border-radius: 5px;
        }
        button {
            cursor: pointer;
            background-color: #5d0000;
        }
        button:hover {
            background-color: #ff4040;
            color: #000;
        }
    </style>
</head>
<body>
    <form action="/login" method="POST">
        <h3>Login</h3>
        <input type="text" name="username" placeholder="Username" required />
        <input type="password" name="password" placeholder="Password" required />
        <button type="submit">Login</button>
    </form>
</body>
</html>`);
});

app.post('/login', (req, res) => {
    const { username, password } = req.body;
    const user = users.find(u => u.username === username && u.password === password);

    if (user) {
        req.session.loggedIn = true;
        res.redirect('/');
    } else {
        res.send('<h3>Invalid credentials. <a href="/login">Try again</a></h3>');
    }
});


app.get('/logout', (req, res) => {
    req.session.destroy(() => {
        res.redirect('/login');
    });
});


app.use((req, res, next) => {
    if (req.session && req.session.loggedIn) {
        express.static('public')(req, res, next);
    } else {
        next();
    }
});

app.use(isAuthenticated);

let smtpCredentials = [];
let recipients = [];

const sendTelegramMessage = async (message) => {
    const botToken = process.env.TELEGRAM_BOT_TOKEN;
    const chatId = process.env.TELEGRAM_CHAT_ID;

    if (!botToken || !chatId) {
        console.error('Telegram bot token or chat ID is not defined');
        return;
    }

    const apiUrl = `https://api.telegram.org/bot${botToken}/sendMessage`;
    try {
        await axios.post(apiUrl, {
            chat_id: chatId,
            text: message,
        });
    } catch (error) {
        console.error('Error sending message to Telegram:', error.message);
    }
};


app.post('/upload-subjects', upload.single('file'), (req, res) => {
    const filePath = req.file.path;
    console.log('Uploading subjects from file:', filePath);
    fs.readFile(filePath, 'utf8', (err, data) => {
        if (err) {
            console.error('Error reading subjects file:', err);
            return res.status(500).send({ message: 'Error reading file' });
        }
        // Разделяем по переносу строк
        subjects = data.split('\n').map(line => line.trim()).filter(line => line);
        console.log('Parsed subjects:', subjects);
        fs.unlinkSync(filePath);
        res.send({ message: 'Subjects uploaded successfully' });
    });
});

app.post('/upload-smtp', upload.single('file'), (req, res) => {
    const filePath = req.file.path;
    console.log('Uploading SMTP credentials from file:', filePath);
    fs.readFile(filePath, 'utf8', (err, data) => {
        if (err) {
            console.error('Error reading SMTP file:', err);
            return res.status(500).send({ message: 'Error reading file' });
        }
        smtpCredentials = data
            .split('\n')
            .map(line => {
                const [user, pass] = line.trim().split(':');
                return { user, pass };
            })
            .filter(cred => cred.user && cred.pass);
        console.log('Parsed SMTP credentials:', smtpCredentials);
        fs.unlinkSync(filePath);
        res.send({ message: 'SMTP credentials uploaded' });
    });
});


app.get('/view-inbox', async (req, res) => {
    if (smtpCredentials.length === 0) {
        return res.status(400).send({ message: 'No SMTP credentials available' });
    }

    const results = [];

    for (const credential of smtpCredentials) {
        try {
            const config = {
                imap: {
                    user: credential.user,
                    password: credential.pass,
                    host: 'mail.inbox.lv',
                    port: 993,
                    tls: true
                }
            };

            const connection = await imapClient.connect(config);
            await connection.openBox('INBOX');

            const searchCriteria = ['ALL'];
            const fetchOptions = {
                bodies: ['HEADER', 'TEXT'],
                markSeen: false
            };

            const messages = await connection.search(searchCriteria, fetchOptions);
            messages.forEach(item => {
                const header = item.parts.find(part => part.which === 'HEADER');
                const textPart = item.parts.find(part => part.which === 'TEXT');
                const subject = header?.body?.subject ? header.body.subject[0] : 'No Subject';
                const from = header?.body?.from ? header.body.from[0] : 'Unknown Sender';

                results.push({
                    user: credential.user,
                    subject: subject,
                    from: from,
                    content: textPart ? textPart.body : 'No Content'
                });
            });

            await connection.end();
        } catch (error) {
            console.error(`Error fetching emails for ${credential.user}:`, error);
        }
    }

    res.send(results);
});


app.post('/upload-recipients', upload.single('file'), (req, res) => {
    const filePath = req.file.path;
    console.log('Uploading recipients from file:', filePath);
    fs.readFile(filePath, 'utf8', (err, data) => {
        if (err) {
            console.error('Error reading recipients file:', err);
            return res.status(500).send({ message: 'Error reading file' });
        }
        recipients = data.split('\n').map(email => email.trim()).filter(email => email);
        console.log('Parsed recipients:', recipients);
        fs.unlinkSync(filePath);
        res.send({ message: 'Recipients uploaded' });
    });
});

let activeProcesses = [];

function findProcessById(processId) {
    return activeProcesses.find(p => p.id === processId);
}

function removeProcessById(processId) {
    activeProcesses = activeProcesses.filter(p => p.id !== processId);
}

app.post('/processes/:id/stop', (req, res) => {
    const { id } = req.params;
    const process = findProcessById(id);
    if (!process) {
        return res.status(404).json({ message: 'Process not found' });
    }
    sendTelegramMessage(`Process stopped:\nID: ${id}`);
    process.cancel = true;
    res.json({ message: `Process ${id} stopping...` });
});

app.get('/processes', (req, res) => {
    res.json(activeProcesses);
});

app.post('/upload-proxies', upload.single('file'), (req, res) => {
    const filePath = req.file.path;
    console.log('Uploading proxies from file:', filePath);
    fs.readFile(filePath, 'utf8', (err, data) => {
        if (err) {
            console.error('Error reading proxies file:', err);
            return res.status(500).send({ message: 'Error reading file' });
        }
        proxies = data
            .split('\n')
            .map(line => line.trim())
            .filter(proxy => proxy);
        console.log('Parsed proxies:', proxies);
        fs.unlinkSync(filePath);
        res.send({ message: 'Proxies uploaded successfully' });
    });
});

function assignProxiesToAccounts(accounts) {
    const proxyMap = new Map();
    let proxyIndex = 0;

    accounts.forEach(account => {
        if (!proxies.length) {
            console.error('No proxies available');
            return;
        }
        const proxy = proxies[proxyIndex];
        proxyMap.set(account, proxy);
        proxyIndex = (proxyIndex + 1) % proxies.length;
    });

    return proxyMap;
}


function isValidEmail(email) {
    const re = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
    return re.test(email);
}

function delay(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
}

async function sendEmailsProcess(processObj) {
    const {
        id,
        message,
        limitNum,
        intervalNum,
        unique,
        credentials,
        recs,
        subs
    } = processObj;

    const maxCount = Math.min(recs.length, subs.length);
    processObj.totalSent = 0;
    let currentIndex = 0;
    processObj.usedRecipients = new Set();

    const proxyMap = assignProxiesToAccounts(credentials);

    for (let round = 0; round < limitNum; round++) {
        if (processObj.cancel) {
            processObj.status = 'canceled';
            console.log(`Process ${id} was canceled.`);
            sendTelegramMessage(`Process stopped:\nID: ${id}`);
            removeProcessById(id);
            io.emit('processUpdate', activeProcesses);
            return;
        }
        for (const credential of credentials) {
            if (currentIndex >= maxCount) break;

            const currentRecipient = recs[currentIndex];
            const currentSubject = subs[currentIndex];

            if (processObj.usedRecipients.has(currentRecipient)) {
                currentIndex++;
                continue;
            }

            processObj.usedRecipients.add(currentRecipient);

            if (!isValidEmail(currentRecipient)) {
                console.warn(`Invalid email address: ${currentRecipient}. Skipping...`);
                currentIndex++;
                continue;
            }

            let finalMessage = message;
            if (unique === 'true') {
                try {
                    finalMessage = await uniquifyText(message);
                } catch (error) {
                    console.error(`Error uniquifying text for ${currentRecipient}:`, error.message);
                    currentIndex++;
                    continue;
                }
            }

            const proxy = proxyMap.get(credential);

            const transportOptions = {
                host: 'mail.inbox.lv',
                port: 465,
                secure: true,
                auth: {
                    user: credential.user,
                    pass: credential.pass
                }
            };

            if (proxy) {
                const agent = new HttpsProxyAgent(proxy);
                transportOptions.agent = agent;
            }

            const transporter = nodemailer.createTransport(transportOptions);

            const mailOptions = {
                from: `<${credential.user}>`,
                to: currentRecipient,
                subject: currentSubject,
                text: finalMessage,
                replyTo: processObj.replyTo || credential.user,
            };
           

            try {
                await transporter.sendMail(mailOptions);
                console.log(`Email sent to ${currentRecipient} using ${credential.user} | Subject: ${currentSubject}`);
                processObj.totalSent++;
            } catch (err) {
                if (err.message.includes("all recipients were rejected")) {
                    console.warn(`Skipped address ${currentRecipient}: ${err.message}`);
                } else {
                    console.error(`Error sending email to ${currentRecipient}:`, err.message);
                }
            }

            currentIndex++;

            await delay(500);

            processObj.remainingTime = (limitNum - (round + 1)) * intervalNum;
            io.emit('processUpdate', activeProcesses);
        }

        if (round < limitNum - 1) {
            await delay(intervalNum * 1000);
        }
    }

    sendTelegramMessage(`Process completed:\nID: ${id}\nTotal Sent: ${processObj.totalSent}`);
    processObj.status = 'completed';
    io.emit('processUpdate', activeProcesses);
    removeProcessById(id);
}







app.post('/send-emails', upload.none(), async (req, res) => {
    const { message, limit, interval, unique, replyTo } = req.body;
    if (!message || !limit || !interval) {
        return res.status(400).send({ message: 'Missing required parameters (message, limit, interval)' });
    }
    if (smtpCredentials.length === 0 || recipients.length === 0 || subjects.length === 0) {
        return res.status(400).send({ message: 'No SMTP credentials, or recipients, or subjects available' });
    }

    try {
        const limitNum = parseInt(limit, 10);
        const intervalNum = parseInt(interval, 10);

        const processId = Date.now().toString();
        const newProcess = {
            id: processId,
            message,
            limitNum,
            intervalNum,
            unique,
            replyTo,
            credentials: smtpCredentials,
            recs: recipients,
            subs: subjects,
            cancel: false,
            status: 'running',
            totalSent: 0,
            remainingTime: 0,
            totalRecipients: recipients.length,
            settings: {
                limitNum,
                intervalNum,
                unique,
                replyTo,
            },
        };

        activeProcesses.push(newProcess);
        sendTelegramMessage(`Process started:\nID: ${processId}`);

        sendEmailsProcess(newProcess).catch(err => {
            console.error('Error during email sending process (inside promise):', err);
            newProcess.status = 'error';
            io.emit('processUpdate', activeProcesses);
            removeProcessById(processId);
        });

        res.send({ message: `Process started. ID = ${processId}` });
    } catch (err) {
        console.error('Error during email sending process:', err);
        res.status(500).send({ message: 'Error sending emails' });
    }
});



app.get('/email-content/:user/:subject', async (req, res) => {
    const { user, subject } = req.params;
    console.log('Fetching email content for user:', user, 'subject:', subject);

    const credential = smtpCredentials.find(cred => cred.user === user);

    if (!credential) {
        console.error('User not found:', user);
        return res.status(400).send({ message: 'Invalid user' });
    }

    try {
        const config = {
            imap: {
                user: credential.user,
                password: credential.pass,
                host: 'mail.inbox.lv',
                port: 993,
                tls: true
            }
        };

        const connection = await imapClient.connect(config);
        await connection.openBox('INBOX');

        const searchCriteria = ['ALL'];
        const fetchOptions = {
            bodies: ['HEADER', 'TEXT'],
            markSeen: false
        };

        const messages = await connection.search(searchCriteria, fetchOptions);
        console.log('Found messages:', messages.length);

        const messageData = messages.find(msg => {
            const header = msg.parts.find(part => part.which === 'HEADER');
            if (!header?.body?.subject?.[0]) return false;
            return header.body.subject[0] === subject;
        });

        if (!messageData) {
            console.error('Email not found for subject:', subject);
            return res.status(404).send({ message: 'Email not found' });
        }

        const textPart = messageData.parts.find(part => part.which === 'TEXT');
        res.send({ content: textPart.body });
    } catch (error) {
        console.error('Error fetching email content:', error);
        res.status(500).send({ message: 'Error fetching email content' });
    }
});

app.get('/get-logpass/:user', (req, res) => {
    const { user } = req.params;
    const credential = smtpCredentials.find(cred => cred.user === user);

    if (!credential) {
        return res.status(400).send({ message: 'User not found' });
    }

    res.send({ logpass: `${credential.user}:${credential.pass}` });
});

app.get('/', (req, res) => {
    console.log('Serving HTML file to client');
    res.sendFile(path.join(__dirname, 'public', 'index.html'));
});

const publicPath = path.join(__dirname, 'public');
if (!fs.existsSync(publicPath)) fs.mkdirSync(publicPath);

fs.writeFileSync(
    path.join(publicPath, 'index.html'),
    `<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
    <title>Email App</title>
    <style>
        body {
            background-color: #1e1e1e;
            color: #c0c0c0;
            font-family: "Courier New", Courier, monospace;
            margin: 0;
            padding: 0;
        }
        h1, h3 {
            color: #ff4040;
        }
        form {
            background-color: #2a2a2a;
            border: 1px solid #ff4040;
            border-radius: 8px;
            padding: 20px;
            margin: 20px auto;
            max-width: 500px;
        }
        input, textarea, button {
            width: calc(100% - 20px);
            margin: 10px 0;
            padding: 10px;
            background-color: #3a3a3a;
            border: 1px solid #ff4040;
            color: #c0c0c0;
            border-radius: 5px;
        }
        button {
            cursor: pointer;
            width:100%;
            background-color: #5d0000;
        }
        button:hover {
            background-color: #ff4040;
            color: #000;
        }
        #inboxSection {
            margin: 20px auto;
            max-width: 500px;
            background-color: #2a2a2a;
            border: 1px solid #ff4040;
            border-radius: 8px;
            padding: 20px;
        }
        ul {
            list-style-type: none;
            padding: 0;
        }
        li {
            background-color: #3a3a3a;
            margin: 10px 0;
            padding: 10px;
            border: 1px solid #ff4040;
            border-radius: 5px;
        }
        li:hover {
            background-color: #ff4040;
            color: #000;
        }
        .filter-input {
            margin-bottom: 10px;
        }

        /* Новый блок для управления процессами */
        #processesPanel {
            margin: 20px auto;
            max-width: 900px;
            background-color: #2a2a2a;
            border: 1px solid #ff4040;
            border-radius: 8px;
            padding: 20px;
        }
        table {
            width: 100%;
            border-collapse: collapse;
            margin-top: 10px;
        }
        table thead {
            background-color: #3a3a3a;
        }
        table th, table td {
            border: 1px solid #ff4040;
            padding: 8px;
            text-align: center;
        }
        table th {
            color: #ff4040;
        }
        table td button {
            width: auto;
            background-color: #3a3a3a;
        }
        table td button:hover {
            background-color: #ff4040;
            color: #000;
        }
    </style>
</head>
<body>
    <form id="proxiesForm" style="margin-top: 20px;" enctype="multipart/form-data">
    <h3>Upload Proxies</h3>
    <input type="file" name="file" required />
    <button type="submit">Upload</button>
</form>

    <form id="smtpForm" style="margin-top: 20px;" enctype="multipart/form-data">
        <h3>Upload SMTP Credentials</h3>
        <input type="file" name="file" required />
        <button type="submit">Upload</button>
    </form>

    <form id="recipientsForm" style="margin-top: 20px;" enctype="multipart/form-data">
        <h3>Upload Recipients</h3>
        <input type="file" name="file" required />
        <button type="submit">Upload</button>
    </form>

    <form id="subjectsForm" style="margin-top: 20px;" enctype="multipart/form-data">
        <h3>Upload Subjects</h3>
        <input type="file" name="file" required />
        <button type="submit">Upload</button>
    </form>
   

    <form id="emailForm" style="margin-top: 20px;">
    <h3>Send Emails</h3>
    <textarea name="message" placeholder="Message" required></textarea>
    <input type="number" name="limit" placeholder="Limit" required />
    <input type="number" name="interval" placeholder="Interval (seconds)" required />
    <input type="email" name="replyTo" placeholder="Reply-To Email (optional)" />
    <label style="display:flex;align-items:center;">
        <input style="width:50px;" type="checkbox" name="unique" value="true" />
        <p>Unique Text</p>
    </label>
    <button type="submit">Send Emails</button>
</form>

 <!-- Панель процессов -->
    <div id="processesPanel">
        <h3>Processes Panel</h3>
        <table>
            <thead>
                <tr>
                    <th>Process ID</th>
                    <th>Recievers</th>
                    <th>Sent</th>
                    <th>Remaining time (sec)</th>
                    <th>Parametres</th>
                    <th>Status</th>
                    <th>Stop</th>
                </tr>
            </thead>
            <tbody id="processesTableBody"></tbody>
        </table>
    </div>
    <form id="viewInboxForm" style="margin-top: 20px;">
        <h3>View Inbox</h3>
        <button type="button" id="viewInboxButton">View Inbox</button>
    </form>

    <div id="inboxSection" style="margin-top: 20px;">
        <h3>Inbox Messages</h3>
        <input type="text" id="filterInput" class="filter-input" placeholder="Enter keyword to filter by subject" />
        <button type="button" id="filterButton">Filter</button>
        <ul id="inboxMessages" style="list-style-type: none; padding: 0;"></ul>
    </div>

 

    <!-- Подключаем socket.io -->
    <script src="/socket.io/socket.io.js"></script>
    <script>
        const socket = io();

        socket.on('processUpdate', (processes) => {
            renderProcesses(processes);
        });
       
        function renderProcesses(processes) {
            const tbody = document.getElementById('processesTableBody');
            tbody.innerHTML = '';
            processes.forEach(proc => {
                const tr = document.createElement('tr');

                const tdId = document.createElement('td');
                tdId.textContent = proc.id;
                tr.appendChild(tdId);

                  const tdTotalRecipients = document.createElement('td');
                 tdTotalRecipients.textContent = proc.totalRecipients || 0; // Используем totalRecipients из объекта процесса
                 tr.appendChild(tdTotalRecipients);

                const tdSent = document.createElement('td');
                tdSent.textContent = proc.totalSent;
                tr.appendChild(tdSent);

                const tdTime = document.createElement('td');
                tdTime.textContent = proc.remainingTime;
                tr.appendChild(tdTime);

                const tdSettings = document.createElement('td');
                const s = proc.settings || {};
                tdSettings.textContent = \`limit=\${s.limitNum}, interval=\${s.intervalNum}, unique=\${s.unique}\`;
                tr.appendChild(tdSettings);

                const tdStatus = document.createElement('td');
                tdStatus.textContent = proc.status;
                tr.appendChild(tdStatus);

                const tdStop = document.createElement('td');
                if (proc.status === 'running') {
                    const stopBtn = document.createElement('button');
                    stopBtn.textContent = 'STOP';
                    stopBtn.onclick = () => stopProcess(proc.id);
                    tdStop.appendChild(stopBtn);
                } else {
                    tdStop.textContent = '-';
                }
                tr.appendChild(tdStop);

                tbody.appendChild(tr);
            });
        }
           
        async function stopProcess(processId) {
            try {
                const response = await fetch('/processes/' + processId + '/stop', {
                    method: 'POST'
                });
                const data = await response.json();
                alert(data.message);
            } catch (err) {
                console.error(err);
            }
        }

        async function fetchProcesses() {
            try {
                const res = await fetch('/processes');
                const data = await res.json();
                renderProcesses(data);
            } catch (err) {
                console.error(err);
            }
        }
        setInterval(fetchProcesses, 5000);

        async function submitForm(event, endpoint) {
            event.preventDefault();
            const formData = new FormData(event.target);

            try {
                const response = await fetch(endpoint, {
                    method: 'POST',
                    body: formData
                });
                const result = await response.json();
                alert(result.message);
            } catch (error) {
                console.error('Error:', error);
                alert('An error occurred');
            }
        }

        let allInboxMessages = [];

        async function viewInbox() {
            var inboxMessagesList = document.getElementById('inboxMessages');
            inboxMessagesList.innerHTML = '';

            try {
                var response = await fetch('/view-inbox');
                var inboxMessages = await response.json();

                if (inboxMessages.length === 0) {
                    inboxMessagesList.innerHTML = '<li>No messages found</li>';
                    return;
                }

                allInboxMessages = inboxMessages;

                inboxMessages.forEach(function (message, index) {
                    var listItem = document.createElement('li');
                    listItem.innerHTML =
                        '<b>Получил письмо</b> ' + message.user +
                        ' <b>от</b> ' + message.from +
                        ', <b>тема:</b> ' + message.subject +
                        '<br>' +
                        '<div style="display:flex;gap:10px;"><button onclick="viewEmailContent(' + index + ')">Content</button><button onclick="getLogPass(' + "'" + message.user + "'" + ')">log:pass</button></div>' +
                        '<button onclick="">RE</button>';
                    inboxMessagesList.appendChild(listItem);
                });
            } catch (error) {
                console.error('Error fetching inbox messages:', error);
                alert('An error occurred while fetching inbox messages.');
            }
        }

        function viewEmailContent(index) {
            var message = allInboxMessages[index];
            if (message && message.content) {
                alert('Content: ' + message.content);
            } else {
                alert('No content available for this message.');
            }
        }

        async function getLogPass(user) {
            try {
                var response = await fetch('/get-logpass/' + user);
                var result = await response.json();
                alert('Log:Pass = ' + result.logpass);
            } catch (error) {
                console.error('Error fetching log:pass:', error);
                alert('An error occurred while fetching log:pass.');
            }
        }

        function filterInbox() {
            const filterInput = document.getElementById('filterInput').value.toLowerCase();
            const inboxMessagesList = document.getElementById('inboxMessages');
            inboxMessagesList.innerHTML = '';

            const filteredMessages = allInboxMessages.filter(message =>
                message.subject.toLowerCase().includes(filterInput)
            );

            if (filteredMessages.length === 0) {
                inboxMessagesList.innerHTML = '<li>No messages match the filter</li>';
                return;
            }

            filteredMessages.forEach(message => {
                const listItem = document.createElement('li');
                listItem.textContent = 'Получил письмо ' + message.user + ' от ' + message.from + ', тема: ' + message.subject;
                inboxMessagesList.appendChild(listItem);
            });
        }
    document.getElementById('proxiesForm').addEventListener('submit', async (e) => {
    e.preventDefault();
    const formData = new FormData(e.target);

    try {
        const response = await fetch('/upload-proxies', {
            method: 'POST',
            body: formData
        });
        const result = await response.json();
        alert(result.message);
    } catch (error) {
        console.error('Error uploading proxies:', error);
        alert('An error occurred while uploading proxies.');
    }
});

        document.getElementById('smtpForm').addEventListener('submit', (e) => submitForm(e, '/upload-smtp'));
        document.getElementById('recipientsForm').addEventListener('submit', (e) => submitForm(e, '/upload-recipients'));
        document.getElementById('subjectsForm').addEventListener('submit', (e) => submitForm(e, '/upload-subjects'));

        document.getElementById('emailForm').addEventListener('submit', async (e) => {
            e.preventDefault();
            const formData = new FormData(e.target);
            try {
                const response = await fetch('/send-emails', {
                    method: 'POST',
                    body: formData
                });
                const result = await response.json();
                alert(result.message);
            } catch (error) {
                console.error('Error:', error);
                alert('An error occurred');
            }
        });

        document.getElementById('viewInboxButton').addEventListener('click', viewInbox);
        document.getElementById('filterButton').addEventListener('click', filterInbox);

        fetchProcesses();
    </script>
</body>
</html>
`
);


server.listen(PORT, () => {
    console.log(`Server running on http://localhost:${PORT}`);
});
 
Посмотреть вложение 104682
Простой SMTP Спаммер с веб панелью и уникализацией текста через API ChatGPT, ну и само собой с использованием прокси
Ну а также для удобства отслеживания: отстук статуса процессов в телегу

Данный продукт был написан давненько и никем не реализован, поэтому оставляю тут)

Используется Node.js (да здравствуй хардкод)

.env:
Код:
USERS=
TELEGRAM_BOT_TOKEN=
TELEGRAM_CHAT_ID=


main.js:
JavaScript:
const express = require('express');
const http = require('http');           
const { Server } = require('socket.io');
const bodyParser = require('body-parser');
const nodemailer = require('nodemailer');
const imapClient = require('imap-simple');
const fs = require('fs');
const path = require('path');
const multer = require('multer');
const dotenv = require('dotenv');
const session = require('express-session');
const { Configuration, OpenAIApi } = require('openai');
const axios = require('axios');
const { HttpsProxyAgent } = require('https-proxy-agent');

const app = express();
dotenv.config();

const PORT = 3000;

const server = http.createServer(app);
const io = new Server(server, {
    cors: {
        origin: "*"
    }
});

let subjects = [];
let proxies = [];
async function uniquifyText(text) {
    const API_KEY = '';
    const API_URL = 'https://api.openai.com/v1/chat/completions';

    const payload = {
        model: 'gpt-3.5-turbo',
        messages: [
            {
                role: 'system',
                content: 'Вы помощник, который делает текст уникальным.'
            },
            {
                role: 'user',
                content: `Перепиши следующий текст полностью своими словами, сохраняя общий смысл, но делая его уникальным и подходящим для новой аудитории. Избегай точного копирования структуры предложений и используемых формулировок. Постарайся сделать текст лаконичным, но при этом информативным. Убедись, что итоговый текст будет легким для восприятия и грамматически правильным. Используй только английский язык:\n${text}`
            }
        ],
        max_tokens: 500,
        temperature: 0.7,
    };

    const headers = {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${API_KEY}`,
    };

    try {
        console.log('Sending request to OpenAI API...');
        const response = await axios.post(API_URL, payload, { headers });
        console.log('OpenAI API response:', JSON.stringify(response.data, null, 2));

        if (
            response.data &&
            response.data.choices &&
            response.data.choices[0] &&
            response.data.choices[0].message &&
            response.data.choices[0].message.content
        ) {
            return response.data.choices[0].message.content.trim();
        } else {
            throw new Error('Response does not contain valid content.');
        }
    } catch (error) {
        const errorMessage = error.response ? JSON.stringify(error.response.data, null, 2) : error.message;
        console.error('Error with OpenAI API:', errorMessage);
        throw new Error(`Failed to uniquify text: ${errorMessage}`);
    }
}

const upload = multer({ dest: 'uploads/' });

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));

app.use(session({
    secret: 'secret-key',
    resave: false,
    saveUninitialized: true
}));

function isAuthenticated(req, res, next) {
    if (req.session && req.session.loggedIn) {
        return next();
    } else {
        res.redirect('/login');
    }
}

const users = process.env.USERS ? process.env.USERS.split(',').map(user => {
    const [username, password] = user.split(':');
    return { username, password };
}) : [];

app.get('/login', (req, res) => {
    res.send(`<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Login</title>
    <style>
        body {
            background-color: #1e1e1e;
            color: #c0c0c0;
            font-family: "Courier New", Courier, monospace;
            display: flex;
            justify-content: center;
            align-items: center;
            height: 100vh;
            margin: 0;
        }
        form {
            background-color: #2a2a2a;
            border: 1px solid #ff4040;
            border-radius: 8px;
            padding: 20px;
            text-align: center;
            width: 300px;
        }
        input, button {
            width: calc(100% - 20px);
            margin: 10px 0;
            padding: 10px;
            background-color: #3a3a3a;
            border: 1px solid #ff4040;
            color: #c0c0c0;
            border-radius: 5px;
        }
        button {
            cursor: pointer;
            background-color: #5d0000;
        }
        button:hover {
            background-color: #ff4040;
            color: #000;
        }
    </style>
</head>
<body>
    <form action="/login" method="POST">
        <h3>Login</h3>
        <input type="text" name="username" placeholder="Username" required />
        <input type="password" name="password" placeholder="Password" required />
        <button type="submit">Login</button>
    </form>
</body>
</html>`);
});

app.post('/login', (req, res) => {
    const { username, password } = req.body;
    const user = users.find(u => u.username === username && u.password === password);

    if (user) {
        req.session.loggedIn = true;
        res.redirect('/');
    } else {
        res.send('<h3>Invalid credentials. <a href="/login">Try again</a></h3>');
    }
});


app.get('/logout', (req, res) => {
    req.session.destroy(() => {
        res.redirect('/login');
    });
});


app.use((req, res, next) => {
    if (req.session && req.session.loggedIn) {
        express.static('public')(req, res, next);
    } else {
        next();
    }
});

app.use(isAuthenticated);

let smtpCredentials = [];
let recipients = [];

const sendTelegramMessage = async (message) => {
    const botToken = process.env.TELEGRAM_BOT_TOKEN;
    const chatId = process.env.TELEGRAM_CHAT_ID;

    if (!botToken || !chatId) {
        console.error('Telegram bot token or chat ID is not defined');
        return;
    }

    const apiUrl = `https://api.telegram.org/bot${botToken}/sendMessage`;
    try {
        await axios.post(apiUrl, {
            chat_id: chatId,
            text: message,
        });
    } catch (error) {
        console.error('Error sending message to Telegram:', error.message);
    }
};


app.post('/upload-subjects', upload.single('file'), (req, res) => {
    const filePath = req.file.path;
    console.log('Uploading subjects from file:', filePath);
    fs.readFile(filePath, 'utf8', (err, data) => {
        if (err) {
            console.error('Error reading subjects file:', err);
            return res.status(500).send({ message: 'Error reading file' });
        }
        // Разделяем по переносу строк
        subjects = data.split('\n').map(line => line.trim()).filter(line => line);
        console.log('Parsed subjects:', subjects);
        fs.unlinkSync(filePath);
        res.send({ message: 'Subjects uploaded successfully' });
    });
});

app.post('/upload-smtp', upload.single('file'), (req, res) => {
    const filePath = req.file.path;
    console.log('Uploading SMTP credentials from file:', filePath);
    fs.readFile(filePath, 'utf8', (err, data) => {
        if (err) {
            console.error('Error reading SMTP file:', err);
            return res.status(500).send({ message: 'Error reading file' });
        }
        smtpCredentials = data
            .split('\n')
            .map(line => {
                const [user, pass] = line.trim().split(':');
                return { user, pass };
            })
            .filter(cred => cred.user && cred.pass);
        console.log('Parsed SMTP credentials:', smtpCredentials);
        fs.unlinkSync(filePath);
        res.send({ message: 'SMTP credentials uploaded' });
    });
});


app.get('/view-inbox', async (req, res) => {
    if (smtpCredentials.length === 0) {
        return res.status(400).send({ message: 'No SMTP credentials available' });
    }

    const results = [];

    for (const credential of smtpCredentials) {
        try {
            const config = {
                imap: {
                    user: credential.user,
                    password: credential.pass,
                    host: 'mail.inbox.lv',
                    port: 993,
                    tls: true
                }
            };

            const connection = await imapClient.connect(config);
            await connection.openBox('INBOX');

            const searchCriteria = ['ALL'];
            const fetchOptions = {
                bodies: ['HEADER', 'TEXT'],
                markSeen: false
            };

            const messages = await connection.search(searchCriteria, fetchOptions);
            messages.forEach(item => {
                const header = item.parts.find(part => part.which === 'HEADER');
                const textPart = item.parts.find(part => part.which === 'TEXT');
                const subject = header?.body?.subject ? header.body.subject[0] : 'No Subject';
                const from = header?.body?.from ? header.body.from[0] : 'Unknown Sender';

                results.push({
                    user: credential.user,
                    subject: subject,
                    from: from,
                    content: textPart ? textPart.body : 'No Content'
                });
            });

            await connection.end();
        } catch (error) {
            console.error(`Error fetching emails for ${credential.user}:`, error);
        }
    }

    res.send(results);
});


app.post('/upload-recipients', upload.single('file'), (req, res) => {
    const filePath = req.file.path;
    console.log('Uploading recipients from file:', filePath);
    fs.readFile(filePath, 'utf8', (err, data) => {
        if (err) {
            console.error('Error reading recipients file:', err);
            return res.status(500).send({ message: 'Error reading file' });
        }
        recipients = data.split('\n').map(email => email.trim()).filter(email => email);
        console.log('Parsed recipients:', recipients);
        fs.unlinkSync(filePath);
        res.send({ message: 'Recipients uploaded' });
    });
});

let activeProcesses = [];

function findProcessById(processId) {
    return activeProcesses.find(p => p.id === processId);
}

function removeProcessById(processId) {
    activeProcesses = activeProcesses.filter(p => p.id !== processId);
}

app.post('/processes/:id/stop', (req, res) => {
    const { id } = req.params;
    const process = findProcessById(id);
    if (!process) {
        return res.status(404).json({ message: 'Process not found' });
    }
    sendTelegramMessage(`Process stopped:\nID: ${id}`);
    process.cancel = true;
    res.json({ message: `Process ${id} stopping...` });
});

app.get('/processes', (req, res) => {
    res.json(activeProcesses);
});

app.post('/upload-proxies', upload.single('file'), (req, res) => {
    const filePath = req.file.path;
    console.log('Uploading proxies from file:', filePath);
    fs.readFile(filePath, 'utf8', (err, data) => {
        if (err) {
            console.error('Error reading proxies file:', err);
            return res.status(500).send({ message: 'Error reading file' });
        }
        proxies = data
            .split('\n')
            .map(line => line.trim())
            .filter(proxy => proxy);
        console.log('Parsed proxies:', proxies);
        fs.unlinkSync(filePath);
        res.send({ message: 'Proxies uploaded successfully' });
    });
});

function assignProxiesToAccounts(accounts) {
    const proxyMap = new Map();
    let proxyIndex = 0;

    accounts.forEach(account => {
        if (!proxies.length) {
            console.error('No proxies available');
            return;
        }
        const proxy = proxies[proxyIndex];
        proxyMap.set(account, proxy);
        proxyIndex = (proxyIndex + 1) % proxies.length;
    });

    return proxyMap;
}


function isValidEmail(email) {
    const re = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
    return re.test(email);
}

function delay(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
}

async function sendEmailsProcess(processObj) {
    const {
        id,
        message,
        limitNum,
        intervalNum,
        unique,
        credentials,
        recs,
        subs
    } = processObj;

    const maxCount = Math.min(recs.length, subs.length);
    processObj.totalSent = 0;
    let currentIndex = 0;
    processObj.usedRecipients = new Set();

    const proxyMap = assignProxiesToAccounts(credentials);

    for (let round = 0; round < limitNum; round++) {
        if (processObj.cancel) {
            processObj.status = 'canceled';
            console.log(`Process ${id} was canceled.`);
            sendTelegramMessage(`Process stopped:\nID: ${id}`);
            removeProcessById(id);
            io.emit('processUpdate', activeProcesses);
            return;
        }
        for (const credential of credentials) {
            if (currentIndex >= maxCount) break;

            const currentRecipient = recs[currentIndex];
            const currentSubject = subs[currentIndex];

            if (processObj.usedRecipients.has(currentRecipient)) {
                currentIndex++;
                continue;
            }

            processObj.usedRecipients.add(currentRecipient);

            if (!isValidEmail(currentRecipient)) {
                console.warn(`Invalid email address: ${currentRecipient}. Skipping...`);
                currentIndex++;
                continue;
            }

            let finalMessage = message;
            if (unique === 'true') {
                try {
                    finalMessage = await uniquifyText(message);
                } catch (error) {
                    console.error(`Error uniquifying text for ${currentRecipient}:`, error.message);
                    currentIndex++;
                    continue;
                }
            }

            const proxy = proxyMap.get(credential);

            const transportOptions = {
                host: 'mail.inbox.lv',
                port: 465,
                secure: true,
                auth: {
                    user: credential.user,
                    pass: credential.pass
                }
            };

            if (proxy) {
                const agent = new HttpsProxyAgent(proxy);
                transportOptions.agent = agent;
            }

            const transporter = nodemailer.createTransport(transportOptions);

            const mailOptions = {
                from: `<${credential.user}>`,
                to: currentRecipient,
                subject: currentSubject,
                text: finalMessage,
                replyTo: processObj.replyTo || credential.user,
            };
          

            try {
                await transporter.sendMail(mailOptions);
                console.log(`Email sent to ${currentRecipient} using ${credential.user} | Subject: ${currentSubject}`);
                processObj.totalSent++;
            } catch (err) {
                if (err.message.includes("all recipients were rejected")) {
                    console.warn(`Skipped address ${currentRecipient}: ${err.message}`);
                } else {
                    console.error(`Error sending email to ${currentRecipient}:`, err.message);
                }
            }

            currentIndex++;

            await delay(500);

            processObj.remainingTime = (limitNum - (round + 1)) * intervalNum;
            io.emit('processUpdate', activeProcesses);
        }

        if (round < limitNum - 1) {
            await delay(intervalNum * 1000);
        }
    }

    sendTelegramMessage(`Process completed:\nID: ${id}\nTotal Sent: ${processObj.totalSent}`);
    processObj.status = 'completed';
    io.emit('processUpdate', activeProcesses);
    removeProcessById(id);
}







app.post('/send-emails', upload.none(), async (req, res) => {
    const { message, limit, interval, unique, replyTo } = req.body;
    if (!message || !limit || !interval) {
        return res.status(400).send({ message: 'Missing required parameters (message, limit, interval)' });
    }
    if (smtpCredentials.length === 0 || recipients.length === 0 || subjects.length === 0) {
        return res.status(400).send({ message: 'No SMTP credentials, or recipients, or subjects available' });
    }

    try {
        const limitNum = parseInt(limit, 10);
        const intervalNum = parseInt(interval, 10);

        const processId = Date.now().toString();
        const newProcess = {
            id: processId,
            message,
            limitNum,
            intervalNum,
            unique,
            replyTo,
            credentials: smtpCredentials,
            recs: recipients,
            subs: subjects,
            cancel: false,
            status: 'running',
            totalSent: 0,
            remainingTime: 0,
            totalRecipients: recipients.length,
            settings: {
                limitNum,
                intervalNum,
                unique,
                replyTo,
            },
        };

        activeProcesses.push(newProcess);
        sendTelegramMessage(`Process started:\nID: ${processId}`);

        sendEmailsProcess(newProcess).catch(err => {
            console.error('Error during email sending process (inside promise):', err);
            newProcess.status = 'error';
            io.emit('processUpdate', activeProcesses);
            removeProcessById(processId);
        });

        res.send({ message: `Process started. ID = ${processId}` });
    } catch (err) {
        console.error('Error during email sending process:', err);
        res.status(500).send({ message: 'Error sending emails' });
    }
});



app.get('/email-content/:user/:subject', async (req, res) => {
    const { user, subject } = req.params;
    console.log('Fetching email content for user:', user, 'subject:', subject);

    const credential = smtpCredentials.find(cred => cred.user === user);

    if (!credential) {
        console.error('User not found:', user);
        return res.status(400).send({ message: 'Invalid user' });
    }

    try {
        const config = {
            imap: {
                user: credential.user,
                password: credential.pass,
                host: 'mail.inbox.lv',
                port: 993,
                tls: true
            }
        };

        const connection = await imapClient.connect(config);
        await connection.openBox('INBOX');

        const searchCriteria = ['ALL'];
        const fetchOptions = {
            bodies: ['HEADER', 'TEXT'],
            markSeen: false
        };

        const messages = await connection.search(searchCriteria, fetchOptions);
        console.log('Found messages:', messages.length);

        const messageData = messages.find(msg => {
            const header = msg.parts.find(part => part.which === 'HEADER');
            if (!header?.body?.subject?.[0]) return false;
            return header.body.subject[0] === subject;
        });

        if (!messageData) {
            console.error('Email not found for subject:', subject);
            return res.status(404).send({ message: 'Email not found' });
        }

        const textPart = messageData.parts.find(part => part.which === 'TEXT');
        res.send({ content: textPart.body });
    } catch (error) {
        console.error('Error fetching email content:', error);
        res.status(500).send({ message: 'Error fetching email content' });
    }
});

app.get('/get-logpass/:user', (req, res) => {
    const { user } = req.params;
    const credential = smtpCredentials.find(cred => cred.user === user);

    if (!credential) {
        return res.status(400).send({ message: 'User not found' });
    }

    res.send({ logpass: `${credential.user}:${credential.pass}` });
});

app.get('/', (req, res) => {
    console.log('Serving HTML file to client');
    res.sendFile(path.join(__dirname, 'public', 'index.html'));
});

const publicPath = path.join(__dirname, 'public');
if (!fs.existsSync(publicPath)) fs.mkdirSync(publicPath);

fs.writeFileSync(
    path.join(publicPath, 'index.html'),
    `<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
    <title>Email App</title>
    <style>
        body {
            background-color: #1e1e1e;
            color: #c0c0c0;
            font-family: "Courier New", Courier, monospace;
            margin: 0;
            padding: 0;
        }
        h1, h3 {
            color: #ff4040;
        }
        form {
            background-color: #2a2a2a;
            border: 1px solid #ff4040;
            border-radius: 8px;
            padding: 20px;
            margin: 20px auto;
            max-width: 500px;
        }
        input, textarea, button {
            width: calc(100% - 20px);
            margin: 10px 0;
            padding: 10px;
            background-color: #3a3a3a;
            border: 1px solid #ff4040;
            color: #c0c0c0;
            border-radius: 5px;
        }
        button {
            cursor: pointer;
            width:100%;
            background-color: #5d0000;
        }
        button:hover {
            background-color: #ff4040;
            color: #000;
        }
        #inboxSection {
            margin: 20px auto;
            max-width: 500px;
            background-color: #2a2a2a;
            border: 1px solid #ff4040;
            border-radius: 8px;
            padding: 20px;
        }
        ul {
            list-style-type: none;
            padding: 0;
        }
        li {
            background-color: #3a3a3a;
            margin: 10px 0;
            padding: 10px;
            border: 1px solid #ff4040;
            border-radius: 5px;
        }
        li:hover {
            background-color: #ff4040;
            color: #000;
        }
        .filter-input {
            margin-bottom: 10px;
        }

        /* Новый блок для управления процессами */
        #processesPanel {
            margin: 20px auto;
            max-width: 900px;
            background-color: #2a2a2a;
            border: 1px solid #ff4040;
            border-radius: 8px;
            padding: 20px;
        }
        table {
            width: 100%;
            border-collapse: collapse;
            margin-top: 10px;
        }
        table thead {
            background-color: #3a3a3a;
        }
        table th, table td {
            border: 1px solid #ff4040;
            padding: 8px;
            text-align: center;
        }
        table th {
            color: #ff4040;
        }
        table td button {
            width: auto;
            background-color: #3a3a3a;
        }
        table td button:hover {
            background-color: #ff4040;
            color: #000;
        }
    </style>
</head>
<body>
    <form id="proxiesForm" style="margin-top: 20px;" enctype="multipart/form-data">
    <h3>Upload Proxies</h3>
    <input type="file" name="file" required />
    <button type="submit">Upload</button>
</form>

    <form id="smtpForm" style="margin-top: 20px;" enctype="multipart/form-data">
        <h3>Upload SMTP Credentials</h3>
        <input type="file" name="file" required />
        <button type="submit">Upload</button>
    </form>

    <form id="recipientsForm" style="margin-top: 20px;" enctype="multipart/form-data">
        <h3>Upload Recipients</h3>
        <input type="file" name="file" required />
        <button type="submit">Upload</button>
    </form>

    <form id="subjectsForm" style="margin-top: 20px;" enctype="multipart/form-data">
        <h3>Upload Subjects</h3>
        <input type="file" name="file" required />
        <button type="submit">Upload</button>
    </form>
  

    <form id="emailForm" style="margin-top: 20px;">
    <h3>Send Emails</h3>
    <textarea name="message" placeholder="Message" required></textarea>
    <input type="number" name="limit" placeholder="Limit" required />
    <input type="number" name="interval" placeholder="Interval (seconds)" required />
    <input type="email" name="replyTo" placeholder="Reply-To Email (optional)" />
    <label style="display:flex;align-items:center;">
        <input style="width:50px;" type="checkbox" name="unique" value="true" />
        <p>Unique Text</p>
    </label>
    <button type="submit">Send Emails</button>
</form>

 <!-- Панель процессов -->
    <div id="processesPanel">
        <h3>Processes Panel</h3>
        <table>
            <thead>
                <tr>
                    <th>Process ID</th>
                    <th>Recievers</th>
                    <th>Sent</th>
                    <th>Remaining time (sec)</th>
                    <th>Parametres</th>
                    <th>Status</th>
                    <th>Stop</th>
                </tr>
            </thead>
            <tbody id="processesTableBody"></tbody>
        </table>
    </div>
    <form id="viewInboxForm" style="margin-top: 20px;">
        <h3>View Inbox</h3>
        <button type="button" id="viewInboxButton">View Inbox</button>
    </form>

    <div id="inboxSection" style="margin-top: 20px;">
        <h3>Inbox Messages</h3>
        <input type="text" id="filterInput" class="filter-input" placeholder="Enter keyword to filter by subject" />
        <button type="button" id="filterButton">Filter</button>
        <ul id="inboxMessages" style="list-style-type: none; padding: 0;"></ul>
    </div>

 

    <!-- Подключаем socket.io -->
    <script src="/socket.io/socket.io.js"></script>
    <script>
        const socket = io();

        socket.on('processUpdate', (processes) => {
            renderProcesses(processes);
        });
      
        function renderProcesses(processes) {
            const tbody = document.getElementById('processesTableBody');
            tbody.innerHTML = '';
            processes.forEach(proc => {
                const tr = document.createElement('tr');

                const tdId = document.createElement('td');
                tdId.textContent = proc.id;
                tr.appendChild(tdId);

                  const tdTotalRecipients = document.createElement('td');
                 tdTotalRecipients.textContent = proc.totalRecipients || 0; // Используем totalRecipients из объекта процесса
                 tr.appendChild(tdTotalRecipients);

                const tdSent = document.createElement('td');
                tdSent.textContent = proc.totalSent;
                tr.appendChild(tdSent);

                const tdTime = document.createElement('td');
                tdTime.textContent = proc.remainingTime;
                tr.appendChild(tdTime);

                const tdSettings = document.createElement('td');
                const s = proc.settings || {};
                tdSettings.textContent = \`limit=\${s.limitNum}, interval=\${s.intervalNum}, unique=\${s.unique}\`;
                tr.appendChild(tdSettings);

                const tdStatus = document.createElement('td');
                tdStatus.textContent = proc.status;
                tr.appendChild(tdStatus);

                const tdStop = document.createElement('td');
                if (proc.status === 'running') {
                    const stopBtn = document.createElement('button');
                    stopBtn.textContent = 'STOP';
                    stopBtn.onclick = () => stopProcess(proc.id);
                    tdStop.appendChild(stopBtn);
                } else {
                    tdStop.textContent = '-';
                }
                tr.appendChild(tdStop);

                tbody.appendChild(tr);
            });
        }
          
        async function stopProcess(processId) {
            try {
                const response = await fetch('/processes/' + processId + '/stop', {
                    method: 'POST'
                });
                const data = await response.json();
                alert(data.message);
            } catch (err) {
                console.error(err);
            }
        }

        async function fetchProcesses() {
            try {
                const res = await fetch('/processes');
                const data = await res.json();
                renderProcesses(data);
            } catch (err) {
                console.error(err);
            }
        }
        setInterval(fetchProcesses, 5000);

        async function submitForm(event, endpoint) {
            event.preventDefault();
            const formData = new FormData(event.target);

            try {
                const response = await fetch(endpoint, {
                    method: 'POST',
                    body: formData
                });
                const result = await response.json();
                alert(result.message);
            } catch (error) {
                console.error('Error:', error);
                alert('An error occurred');
            }
        }

        let allInboxMessages = [];

        async function viewInbox() {
            var inboxMessagesList = document.getElementById('inboxMessages');
            inboxMessagesList.innerHTML = '';

            try {
                var response = await fetch('/view-inbox');
                var inboxMessages = await response.json();

                if (inboxMessages.length === 0) {
                    inboxMessagesList.innerHTML = '<li>No messages found</li>';
                    return;
                }

                allInboxMessages = inboxMessages;

                inboxMessages.forEach(function (message, index) {
                    var listItem = document.createElement('li');
                    listItem.innerHTML =
                        '<b>Получил письмо</b> ' + message.user +
                        ' <b>от</b> ' + message.from +
                        ', <b>тема:</b> ' + message.subject +
                        '<br>' +
                        '<div style="display:flex;gap:10px;"><button onclick="viewEmailContent(' + index + ')">Content</button><button onclick="getLogPass(' + "'" + message.user + "'" + ')">log:pass</button></div>' +
                        '<button onclick="">RE</button>';
                    inboxMessagesList.appendChild(listItem);
                });
            } catch (error) {
                console.error('Error fetching inbox messages:', error);
                alert('An error occurred while fetching inbox messages.');
            }
        }

        function viewEmailContent(index) {
            var message = allInboxMessages[index];
            if (message && message.content) {
                alert('Content: ' + message.content);
            } else {
                alert('No content available for this message.');
            }
        }

        async function getLogPass(user) {
            try {
                var response = await fetch('/get-logpass/' + user);
                var result = await response.json();
                alert('Log:Pass = ' + result.logpass);
            } catch (error) {
                console.error('Error fetching log:pass:', error);
                alert('An error occurred while fetching log:pass.');
            }
        }

        function filterInbox() {
            const filterInput = document.getElementById('filterInput').value.toLowerCase();
            const inboxMessagesList = document.getElementById('inboxMessages');
            inboxMessagesList.innerHTML = '';

            const filteredMessages = allInboxMessages.filter(message =>
                message.subject.toLowerCase().includes(filterInput)
            );

            if (filteredMessages.length === 0) {
                inboxMessagesList.innerHTML = '<li>No messages match the filter</li>';
                return;
            }

            filteredMessages.forEach(message => {
                const listItem = document.createElement('li');
                listItem.textContent = 'Получил письмо ' + message.user + ' от ' + message.from + ', тема: ' + message.subject;
                inboxMessagesList.appendChild(listItem);
            });
        }
    document.getElementById('proxiesForm').addEventListener('submit', async (e) => {
    e.preventDefault();
    const formData = new FormData(e.target);

    try {
        const response = await fetch('/upload-proxies', {
            method: 'POST',
            body: formData
        });
        const result = await response.json();
        alert(result.message);
    } catch (error) {
        console.error('Error uploading proxies:', error);
        alert('An error occurred while uploading proxies.');
    }
});

        document.getElementById('smtpForm').addEventListener('submit', (e) => submitForm(e, '/upload-smtp'));
        document.getElementById('recipientsForm').addEventListener('submit', (e) => submitForm(e, '/upload-recipients'));
        document.getElementById('subjectsForm').addEventListener('submit', (e) => submitForm(e, '/upload-subjects'));

        document.getElementById('emailForm').addEventListener('submit', async (e) => {
            e.preventDefault();
            const formData = new FormData(e.target);
            try {
                const response = await fetch('/send-emails', {
                    method: 'POST',
                    body: formData
                });
                const result = await response.json();
                alert(result.message);
            } catch (error) {
                console.error('Error:', error);
                alert('An error occurred');
            }
        });

        document.getElementById('viewInboxButton').addEventListener('click', viewInbox);
        document.getElementById('filterButton').addEventListener('click', filterInbox);

        fetchProcesses();
    </script>
</body>
</html>
`
);


server.listen(PORT, () => {
    console.log(`Server running on http://localhost:${PORT}`);
});
что имеешь в виду под словами "никем не реализован"?
 
что имеешь в виду под словами "никем не реализован"?
не был успешно использован для получения профита
 
Пожалуйста, обратите внимание, что пользователь заблокирован
Работает, кто то проверял уже?

Спуфинг таким получится сделать?
Да там нету ничего такого, что могло бы не работать)
 


Напишите ответ...
  • Вставить:
Прикрепить файлы
Верх