Files
newsletter_spammer/index.js
T
2026-02-14 18:07:55 +01:00

168 lines
5.9 KiB
JavaScript

const fs = require('fs');
const path = require('path');
const toml = require('@iarna/toml');
const puppeteer = require('puppeteer-extra');
const StealthPlugin = require('puppeteer-extra-plugin-stealth');
puppeteer.use(StealthPlugin());
// --- Helper Functions ---
function loadConfig() {
try {
const configPath = path.join(__dirname, 'config.toml');
const tomlString = fs.readFileSync(configPath, 'utf-8');
const config = toml.parse(tomlString);
console.log('✅ Configuration loaded successfully.');
return config;
} catch (error) {
console.error('❌ Failed to load or parse config.toml:', error.message);
process.exit(1);
}
}
function generateRandomData() {
const randomString = Math.random().toString(36).substring(2, 10);
const username = `user${randomString}`;
const email = `${username}@gmail.com`;
const password = `pass${randomString}`;
const age = Math.floor(Math.random() * 30 + 20).toString(); // Random age between 20-49
return { username, email, password, age };
}
/**
* Parses a locator string. If it's an HTML snippet, it generates a CSS selector.
* If it's already a selector, it returns it as is.
* @param {string} locatorStr - The locator string from the config.
* @returns {string} A CSS selector.
*/
function parseLocator(locatorStr) {
locatorStr = locatorStr.trim();
if (!locatorStr.startsWith('<')) {
return locatorStr; // It's already a selector
}
const getAttr = (attr) => {
const match = locatorStr.match(new RegExp(`${attr}=["']([^"']+)["']`));
return match ? match[1] : null;
};
const tagName = (locatorStr.match(/^<([a-zA-Z0-9]+)/) || [])[1] || '';
const id = getAttr('id');
// FIX: Handle numeric IDs by creating an attribute selector
if (id) {
if (/^\\d/.test(id)) { // If id starts with a digit
return `${tagName}[id='${id}']`;
}
return `${tagName}#${id}`;
}
const name = getAttr('name');
if (name) return `${tagName}[name='${name}']`;
const placeholder = getAttr('placeholder');
if (placeholder) return `${tagName}[placeholder='${placeholder}']`;
const type = getAttr('type');
if (type) return `${tagName}[type='${type}']`;
console.warn(`Could not generate a reliable selector for: ${locatorStr}.`);
return tagName;
}
async function handleCameraBoysGDPR(page) {
// ... (This function remains the same)
}
// --- Main Execution ---
async function main() {
const config = loadConfig();
const sitesToProcess = config.sites || [];
const browserConfig = config.browser || {};
const globalCreds = config.global_credentials || {};
const userDataDir = browserConfig.userDataDir;
if (!userDataDir) {
console.error('❌ userDataDir is not set in config.toml. This is required.');
return;
}
const browser = await puppeteer.launch({
headless: false,
userDataDir: userDataDir,
args: ["--start-maximized"]
});
try {
let isFirstSite = true;
for (const site of sitesToProcess) {
let creds;
if (site.credentials && site.credentials.username) {
creds = { ...globalCreds, ...site.credentials };
console.log(`Using credentials specified for site: ${site.name}`);
} else {
creds = { ...globalCreds };
console.log(`Using global credentials for site: ${site.name}`);
}
// If any credential is still missing, generate it randomly
if (!creds.username || !creds.email || !creds.password || !creds.age) {
const randomData = generateRandomData();
creds = { ...randomData, ...creds };
console.log('Filled in missing credentials with random data.');
}
console.log(`\n--- Processing Site: ${site.name} (Category: ${site.category || 'N/A'}) ---`);
const page = isFirstSite ? (await browser.pages())[0] : await browser.newPage();
isFirstSite = false;
if (browserConfig.userAgent) {
await page.setUserAgent(browserConfig.userAgent);
}
await page.goto(site.url, { waitUntil: 'networkidle2' });
if (site.needsPreSubmitAction && site.name === 'CameraBoys') {
await handleCameraBoysGDPR(page);
}
console.log('Dynamically filling out the form...');
const definedLocators = site.locators || {};
for (const fieldName in definedLocators) {
if (fieldName === 'submit') continue; // Skip the submit button
const selector = parseLocator(definedLocators[fieldName]);
let valueToFill = creds[fieldName];
// Special case for 'confirmEmail', use the email value
if (fieldName === 'confirmEmail') {
valueToFill = creds['email'];
}
if (selector && valueToFill) {
try {
console.log(` - Filling field: ${fieldName}`);
await page.type(selector, valueToFill, { delay: 100 });
} catch (e) {
console.warn(` - Could not fill field '${fieldName}' with selector '${selector}'. Error: ${e.message}`);
}
}
}
console.log('Form filled. Attempting to submit...');
const submitSelector = parseLocator(definedLocators.submit);
await page.click(submitSelector);
console.log(`✅ Submission attempt for ${site.name} is complete.`);
}
} catch(error) {
console.error('❌ A critical error occurred during execution:', error.message);
} finally {
console.log('\n🎉 All tasks complete. The browser window will remain open for inspection.');
}
}
main();