const express = require("express"); const puppeteer = require("puppeteer-extra"); const StealthPlugin = require("puppeteer-extra-plugin-stealth"); const cheerio = require("cheerio"); require('dotenv').config(); // Add stealth plugin puppeteer.use(StealthPlugin()); const app = express(); const PORT = 7860; // Browser instance management let browser = null; let authenticatedPage = null; let isLoggedIn = false; async function getBrowser() { if (!browser) { browser = await puppeteer.launch({ headless: "new", // Use new headless mode args: [ '--no-sandbox', '--disable-setuid-sandbox', '--disable-dev-shm-usage', '--disable-accelerated-2d-canvas', '--no-first-run', '--no-zygote', '--disable-gpu', '--disable-web-security', '--disable-features=VizDisplayCompositor' ] }); } return browser; } // Get or create authenticated page async function getAuthenticatedPage() { if (!authenticatedPage || authenticatedPage.isClosed()) { const browser = await getBrowser(); authenticatedPage = await setupPage(browser); isLoggedIn = false; // Reset login status for new page } return authenticatedPage; } // Login function with extensive debugging async function performLogin() { if (isLoggedIn) return true; const page = await getAuthenticatedPage(); try { console.log('Performing login...'); console.log('Using email:', process.env.LOGIN_EMAIL ? 'Found' : 'Missing'); console.log('Using password:', process.env.LOGIN_PASSWORD ? 'Found' : 'Missing'); // Navigate to login page await page.goto('https://getsms.cc/auth/login', { waitUntil: 'networkidle2', timeout: 30000 }); console.log('Loaded login page'); // Wait for form to be visible await page.waitForSelector('form#login', { timeout: 10000 }); console.log('Found login form'); // Take screenshot before login (for debugging) // await page.screenshot({ path: 'before-login.png' }); // Clear and fill email field await page.evaluate(() => { const emailField = document.querySelector('input[name="mail"]'); if (emailField) emailField.value = ''; }); await page.focus('input[name="mail"]'); await page.type('input[name="mail"]', process.env.LOGIN_EMAIL, { delay: 50 }); // Clear and fill password field await page.evaluate(() => { const passwordField = document.querySelector('input[name="password"]'); if (passwordField) passwordField.value = ''; }); await page.focus('input[name="password"]'); await page.type('input[name="password"]', process.env.LOGIN_PASSWORD, { delay: 50 }); console.log('Filled login form'); // Wait a moment before submitting await new Promise(resolve => setTimeout(resolve, 1000)); // Submit form with different approach await page.evaluate(() => { const form = document.querySelector('form#login'); if (form) { form.submit(); } }); console.log('Submitted form, waiting for response...'); // Wait for either navigation or page update try { await page.waitForNavigation({ waitUntil: 'networkidle2', timeout: 15000 }); console.log('Navigation detected'); } catch (e) { console.log('No navigation, checking for page updates...'); await new Promise(resolve => setTimeout(resolve, 3000)); } const currentUrl = page.url(); console.log('Current URL after login attempt:', currentUrl); // Take screenshot after login (for debugging) // await page.screenshot({ path: 'after-login.png' }); // Check for error messages on the page const errorMessage = await page.evaluate(() => { const errorElements = document.querySelectorAll('.alert-danger, .text-danger, .error, .alert-error'); for (let el of errorElements) { if (el.textContent.trim()) { return el.textContent.trim(); } } return null; }); if (errorMessage) { console.log('Login error message:', errorMessage); return false; } // More comprehensive login success check const loginCheck = await page.evaluate(() => { const url = window.location.href; const bodyText = document.body.innerText.toLowerCase(); // Check various indicators of successful login const indicators = { notOnLoginPage: !url.includes('/auth/login'), hasLogoutLink: document.querySelector('[href*="logout"]') !== null, hasUserDropdown: document.querySelector('.dropdown-toggle') !== null, hasUserProfile: document.querySelector('.user-profile') !== null, hasDashboard: bodyText.includes('dashboard'), hasWelcome: bodyText.includes('welcome'), hasMyAccount: bodyText.includes('my account'), urlIndicatesSuccess: url.includes('/dashboard') || url.includes('/account') || url === 'https://getsms.cc/' }; console.log('Login indicators:', indicators); return { success: Object.values(indicators).some(v => v), indicators, url, pageTitle: document.title }; }); console.log('Login check result:', loginCheck); if (loginCheck.success) { isLoggedIn = true; console.log('✅ Login successful - authenticated session established'); return true; } else { console.log('❌ Login failed - no success indicators found'); // Get page content for debugging const pageContent = await page.evaluate(() => { return document.body.innerText.substring(0, 1000); }); console.log('Page content after login:', pageContent); return false; } } catch (error) { console.error('Login error:', error); return false; } } // Enhanced page setup for maximum stealth async function setupPage(browser) { const page = await browser.newPage(); // Set viewport to common resolution await page.setViewport({ width: 1366, height: 768 }); // Set realistic user agent await page.setUserAgent('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'); // Set additional headers await page.setExtraHTTPHeaders({ 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8', 'Accept-Language': 'en-US,en;q=0.9', 'Accept-Encoding': 'gzip, deflate, br', 'DNT': '1', 'Connection': 'keep-alive', 'Upgrade-Insecure-Requests': '1', }); return page; } // Scraper function for numbers list with stealth async function scrapeUK(pageNum = 1) { const browser = await getBrowser(); const page = await setupPage(browser); try { const url = pageNum === 1 ? "https://getsms.cc/temporary-phone-numbers/UK" : `https://getsms.cc/temporary-phone-numbers/UK/${pageNum}`; // Navigate with realistic options await page.goto(url, { waitUntil: 'networkidle2', timeout: 30000 }); // Add random delay to mimic human behavior await new Promise(resolve => setTimeout(resolve, Math.random() * 2000 + 1000)); // Get page content const content = await page.content(); const $ = cheerio.load(content); const results = []; $(".card").each((i, el) => { const number = $(el).find("p.p-0.m-0.font-weight-bold").text().trim(); const timeAgo = $(el).find("p.p-0.m-0.small").text().trim(); const link = $(el).find("a.btn.btn-primary").attr("href"); if (number && timeAgo && link) { results.push({ number, timeAgo, link: `https://getsms.cc${link}`, }); } }); return results; } catch (error) { console.error('Error scraping UK numbers:', error); throw error; } finally { await page.close(); } } // Scraper function for messages with stealth async function scrapeMessages(number) { const browser = await getBrowser(); const page = await setupPage(browser); try { const url = `https://getsms.cc/info/${number}`; // Navigate with realistic options await page.goto(url, { waitUntil: 'networkidle2', timeout: 30000 }); // Add random delay await new Promise(resolve => setTimeout(resolve, Math.random() * 2000 + 1000)); // Get page content const content = await page.content(); const $ = cheerio.load(content); const messages = []; $(".direct-chat-msg").each((i, el) => { const from = $(el).find(".direct-chat-name").text().trim(); const timeAgo = $(el).find("time").text().trim(); const text = $(el).find(".direct-chat-text").text().trim(); // Skip ads/empty messages if (from && text) { messages.push({ from, timeAgo, text }); } }); // Return latest 3 (newest first) return messages.slice(-3).reverse(); } catch (error) { console.error('Error scraping messages:', error); throw error; } finally { await page.close(); } } // Endpoint: UK numbers app.get(["/uk", "/uk/:page"], async (req, res) => { try { const page = parseInt(req.params.page) || 1; const numbers = await scrapeUK(page); res.json({ country: "United Kingdom", page, count: numbers.length, numbers, }); } catch (err) { console.error("Error:", err.message); res.status(500).json({ error: "Failed to scrape numbers" }); } }); // Endpoint: messages app.get("/msg/:number", async (req, res) => { try { const number = req.params.number; const messages = await scrapeMessages(number); res.json({ number, count: messages.length, messages, }); } catch (err) { console.error("Error:", err.message); res.status(500).json({ error: "Failed to scrape messages" }); } }); // Graceful shutdown process.on('SIGINT', async () => { console.log('Shutting down gracefully...'); if (authenticatedPage && !authenticatedPage.isClosed()) { await authenticatedPage.close(); } if (browser) { await browser.close(); } process.exit(0); }); process.on('SIGTERM', async () => { console.log('Shutting down gracefully...'); if (authenticatedPage && !authenticatedPage.isClosed()) { await authenticatedPage.close(); } if (browser) { await browser.close(); } process.exit(0); }); // Start server app.listen(PORT, () => { console.log(`Server running on http://localhost:${PORT}`); console.log('Using Puppeteer with stealth mode to avoid detection'); });