reikernx commited on
Commit
f56741b
·
verified ·
1 Parent(s): b483071

Update server.js

Browse files
Files changed (1) hide show
  1. server.js +202 -308
server.js CHANGED
@@ -1,340 +1,222 @@
1
- const express = require("express");
2
- const puppeteer = require("puppeteer-extra");
3
- const StealthPlugin = require("puppeteer-extra-plugin-stealth");
4
- const cheerio = require("cheerio");
5
- require('dotenv').config();
6
-
7
- // Add stealth plugin
8
  puppeteer.use(StealthPlugin());
9
 
10
  const app = express();
11
- const PORT = 7860;
12
 
13
- // Browser instance management
14
  let browser = null;
15
- let authenticatedPage = null;
16
- let isLoggedIn = false;
17
-
18
- async function getBrowser() {
19
- if (!browser) {
20
- browser = await puppeteer.launch({
21
- headless: "new", // Use new headless mode
22
- args: [
23
- '--no-sandbox',
24
- '--disable-setuid-sandbox',
25
- '--disable-dev-shm-usage',
26
- '--disable-accelerated-2d-canvas',
27
- '--no-first-run',
28
- '--no-zygote',
29
- '--disable-gpu',
30
- '--disable-web-security',
31
- '--disable-features=VizDisplayCompositor'
32
- ]
33
- });
34
- }
35
- return browser;
36
- }
37
 
38
- // Get or create authenticated page
39
- async function getAuthenticatedPage() {
40
- if (!authenticatedPage || authenticatedPage.isClosed()) {
41
- const browser = await getBrowser();
42
- authenticatedPage = await setupPage(browser);
43
- isLoggedIn = false; // Reset login status for new page
44
- }
45
- return authenticatedPage;
46
- }
47
 
48
- // Login function with extensive debugging
49
- async function performLogin() {
50
- if (isLoggedIn) return true;
51
-
52
- const page = await getAuthenticatedPage();
53
-
54
  try {
55
- console.log('Performing login...');
56
- console.log('Using email:', process.env.LOGIN_EMAIL ? 'Found' : 'Missing');
57
- console.log('Using password:', process.env.LOGIN_PASSWORD ? 'Found' : 'Missing');
58
-
59
- // Navigate to login page
60
- await page.goto('https://getsms.cc/auth/login', {
61
- waitUntil: 'networkidle2',
62
- timeout: 30000
63
- });
64
-
65
- console.log('Loaded login page');
66
-
67
- // Wait for form to be visible
68
- await page.waitForSelector('form#login', { timeout: 10000 });
69
- console.log('Found login form');
70
-
71
- // Take screenshot before login (for debugging)
72
- // await page.screenshot({ path: 'before-login.png' });
73
-
74
- // Clear and fill email field
75
- await page.evaluate(() => {
76
- const emailField = document.querySelector('input[name="mail"]');
77
- if (emailField) emailField.value = '';
78
- });
79
- await page.focus('input[name="mail"]');
80
- await page.type('input[name="mail"]', process.env.LOGIN_EMAIL, { delay: 50 });
81
 
82
- // Clear and fill password field
83
- await page.evaluate(() => {
84
- const passwordField = document.querySelector('input[name="password"]');
85
- if (passwordField) passwordField.value = '';
86
  });
87
- await page.focus('input[name="password"]');
88
- await page.type('input[name="password"]', process.env.LOGIN_PASSWORD, { delay: 50 });
89
-
90
- console.log('Filled login form');
91
-
92
- // Wait a moment before submitting
93
- await new Promise(resolve => setTimeout(resolve, 1000));
94
 
95
- // Submit form with different approach
96
- await page.evaluate(() => {
97
- const form = document.querySelector('form#login');
98
- if (form) {
99
- form.submit();
100
- }
101
  });
 
 
 
 
 
 
 
 
 
 
 
102
 
103
- console.log('Submitted form, waiting for response...');
 
 
 
 
 
 
 
 
 
104
 
105
- // Wait for either navigation or page update
106
- try {
107
- await page.waitForNavigation({ waitUntil: 'networkidle2', timeout: 15000 });
108
- console.log('Navigation detected');
109
- } catch (e) {
110
- console.log('No navigation, checking for page updates...');
111
- await new Promise(resolve => setTimeout(resolve, 3000));
112
  }
113
-
114
- const currentUrl = page.url();
115
- console.log('Current URL after login attempt:', currentUrl);
116
-
117
- // Take screenshot after login (for debugging)
118
- // await page.screenshot({ path: 'after-login.png' });
119
-
120
- // Check for error messages on the page
121
- const errorMessage = await page.evaluate(() => {
122
- const errorElements = document.querySelectorAll('.alert-danger, .text-danger, .error, .alert-error');
123
- for (let el of errorElements) {
124
- if (el.textContent.trim()) {
125
- return el.textContent.trim();
126
- }
127
- }
128
- return null;
129
  });
130
-
131
- if (errorMessage) {
132
- console.log('Login error message:', errorMessage);
133
- return false;
 
134
  }
135
-
136
- // More comprehensive login success check
137
- const loginCheck = await page.evaluate(() => {
138
- const url = window.location.href;
139
- const bodyText = document.body.innerText.toLowerCase();
140
-
141
- // Check various indicators of successful login
142
- const indicators = {
143
- notOnLoginPage: !url.includes('/auth/login'),
144
- hasLogoutLink: document.querySelector('[href*="logout"]') !== null,
145
- hasUserDropdown: document.querySelector('.dropdown-toggle') !== null,
146
- hasUserProfile: document.querySelector('.user-profile') !== null,
147
- hasDashboard: bodyText.includes('dashboard'),
148
- hasWelcome: bodyText.includes('welcome'),
149
- hasMyAccount: bodyText.includes('my account'),
150
- urlIndicatesSuccess: url.includes('/dashboard') || url.includes('/account') || url === 'https://getsms.cc/'
151
- };
152
-
153
- console.log('Login indicators:', indicators);
154
-
155
- return {
156
- success: Object.values(indicators).some(v => v),
157
- indicators,
158
- url,
159
- pageTitle: document.title
160
- };
161
  });
162
-
163
- console.log('Login check result:', loginCheck);
164
-
165
- if (loginCheck.success) {
166
- isLoggedIn = true;
167
- console.log('✅ Login successful - authenticated session established');
168
- return true;
169
- } else {
170
- console.log('❌ Login failed - no success indicators found');
171
 
172
- // Get page content for debugging
173
- const pageContent = await page.evaluate(() => {
174
- return document.body.innerText.substring(0, 1000);
175
  });
176
- console.log('Page content after login:', pageContent);
177
-
178
- return false;
179
- }
180
- } catch (error) {
181
- console.error('Login error:', error);
182
- return false;
183
- }
184
- }
185
 
186
- // Enhanced page setup for maximum stealth
187
- async function setupPage(browser) {
188
- const page = await browser.newPage();
189
-
190
- // Set viewport to common resolution
191
- await page.setViewport({ width: 1366, height: 768 });
192
-
193
- // Set realistic user agent
194
- 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');
195
-
196
- // Set additional headers
197
- await page.setExtraHTTPHeaders({
198
- 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
199
- 'Accept-Language': 'en-US,en;q=0.9',
200
- 'Accept-Encoding': 'gzip, deflate, br',
201
- 'DNT': '1',
202
- 'Connection': 'keep-alive',
203
- 'Upgrade-Insecure-Requests': '1',
204
- });
205
-
206
- return page;
207
- }
208
 
209
- // Scraper function for numbers list with stealth
210
- async function scrapeUK(pageNum = 1) {
211
- const browser = await getBrowser();
212
- const page = await setupPage(browser);
213
-
214
- try {
215
- const url = pageNum === 1
216
- ? "https://getsms.cc/temporary-phone-numbers/UK"
217
- : `https://getsms.cc/temporary-phone-numbers/UK/${pageNum}`;
218
-
219
- // Navigate with realistic options
220
- await page.goto(url, {
221
- waitUntil: 'networkidle2',
222
- timeout: 30000
223
- });
224
-
225
- // Add random delay to mimic human behavior
226
- await new Promise(resolve => setTimeout(resolve, Math.random() * 2000 + 1000));
227
-
228
- // Get page content
229
- const content = await page.content();
230
- const $ = cheerio.load(content);
231
-
232
- const results = [];
233
- $(".card").each((i, el) => {
234
- const number = $(el).find("p.p-0.m-0.font-weight-bold").text().trim();
235
- const timeAgo = $(el).find("p.p-0.m-0.small").text().trim();
236
- const link = $(el).find("a.btn.btn-primary").attr("href");
237
 
238
- if (number && timeAgo && link) {
239
- results.push({
240
- number,
241
- timeAgo,
242
- link: `https://getsms.cc${link}`,
243
- });
244
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
245
  });
246
-
247
- return results;
248
- } catch (error) {
249
- console.error('Error scraping UK numbers:', error);
250
- throw error;
251
- } finally {
252
- await page.close();
253
- }
254
- }
255
 
256
- // Scraper function for messages with stealth
257
- async function scrapeMessages(number) {
258
- const browser = await getBrowser();
259
- const page = await setupPage(browser);
260
-
261
- try {
262
- const url = `https://getsms.cc/info/${number}`;
263
-
264
- // Navigate with realistic options
265
- await page.goto(url, {
266
- waitUntil: 'networkidle2',
267
- timeout: 30000
268
- });
269
-
270
- // Add random delay
271
- await new Promise(resolve => setTimeout(resolve, Math.random() * 2000 + 1000));
272
-
273
- // Get page content
274
- const content = await page.content();
275
- const $ = cheerio.load(content);
276
-
277
- const messages = [];
278
- $(".direct-chat-msg").each((i, el) => {
279
- const from = $(el).find(".direct-chat-name").text().trim();
280
- const timeAgo = $(el).find("time").text().trim();
281
- const text = $(el).find(".direct-chat-text").text().trim();
282
-
283
- // Skip ads/empty messages
284
- if (from && text) {
285
- messages.push({ from, timeAgo, text });
286
  }
287
- });
288
-
289
- // Return latest 3 (newest first)
290
- return messages.slice(-3).reverse();
291
- } catch (error) {
292
- console.error('Error scraping messages:', error);
293
- throw error;
294
- } finally {
295
- await page.close();
296
- }
297
- }
298
 
299
- // Endpoint: UK numbers
300
- app.get(["/uk", "/uk/:page"], async (req, res) => {
301
- try {
302
- const page = parseInt(req.params.page) || 1;
303
- const numbers = await scrapeUK(page);
304
  res.json({
305
- country: "United Kingdom",
306
- page,
307
- count: numbers.length,
308
- numbers,
 
309
  });
310
- } catch (err) {
311
- console.error("Error:", err.message);
312
- res.status(500).json({ error: "Failed to scrape numbers" });
313
- }
314
- });
315
 
316
- // Endpoint: messages
317
- app.get("/msg/:number", async (req, res) => {
318
- try {
319
- const number = req.params.number;
320
- const messages = await scrapeMessages(number);
321
- res.json({
322
- number,
323
- count: messages.length,
324
- messages,
325
  });
326
- } catch (err) {
327
- console.error("Error:", err.message);
328
- res.status(500).json({ error: "Failed to scrape messages" });
329
  }
330
  });
331
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
332
  // Graceful shutdown
333
  process.on('SIGINT', async () => {
334
- console.log('Shutting down gracefully...');
335
- if (authenticatedPage && !authenticatedPage.isClosed()) {
336
- await authenticatedPage.close();
337
- }
338
  if (browser) {
339
  await browser.close();
340
  }
@@ -342,10 +224,7 @@ process.on('SIGINT', async () => {
342
  });
343
 
344
  process.on('SIGTERM', async () => {
345
- console.log('Shutting down gracefully...');
346
- if (authenticatedPage && !authenticatedPage.isClosed()) {
347
- await authenticatedPage.close();
348
- }
349
  if (browser) {
350
  await browser.close();
351
  }
@@ -353,7 +232,22 @@ process.on('SIGTERM', async () => {
353
  });
354
 
355
  // Start server
356
- app.listen(PORT, () => {
357
- console.log(`Server running on http://localhost:${PORT}`);
358
- console.log('Using Puppeteer with stealth mode to avoid detection');
359
- });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ const express = require('express');
2
+ const puppeteer = require('puppeteer-extra');
3
+ const StealthPlugin = require('puppeteer-extra-plugin-stealth');
 
 
 
 
4
  puppeteer.use(StealthPlugin());
5
 
6
  const app = express();
7
+ const PORT = process.env.PORT || 7860;
8
 
9
+ // Store browser instance to reuse
10
  let browser = null;
11
+ let loggedInPage = null;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12
 
13
+ // Middleware
14
+ app.use(express.json());
 
 
 
 
 
 
 
15
 
16
+ // Initialize browser and login once on startup
17
+ async function initializeBrowser() {
 
 
 
 
18
  try {
19
+ console.log('🚀 Initializing browser and logging in...');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20
 
21
+ browser = await puppeteer.launch({
22
+ headless: true, // Set to false for debugging
23
+ args: ["--no-sandbox", "--disable-setuid-sandbox"]
 
24
  });
25
+
26
+ loggedInPage = await browser.newPage();
 
 
 
 
 
27
 
28
+ // Login process
29
+ await loggedInPage.goto("https://getsms.cc/auth/login", {
30
+ waitUntil: "networkidle2"
 
 
 
31
  });
32
+
33
+ // Replace with your actual credentials
34
+ await loggedInPage.type("#email", "your@email.com", { delay: 50 });
35
+ await loggedInPage.type("#password", "yourpassword", { delay: 50 });
36
+
37
+ await Promise.all([
38
+ loggedInPage.click("input[type=submit]"),
39
+ loggedInPage.waitForNavigation({ waitUntil: "networkidle2" })
40
+ ]);
41
+
42
+ console.log("✅ Browser initialized and logged in successfully!");
43
 
44
+ } catch (error) {
45
+ console.error("❌ Failed to initialize browser:", error);
46
+ throw error;
47
+ }
48
+ }
49
+
50
+ // API endpoint to get messages for a phone number
51
+ app.get('/api/messages', async (req, res) => {
52
+ try {
53
+ const { number } = req.query;
54
 
55
+ if (!number) {
56
+ return res.status(400).json({
57
+ error: 'Phone number is required',
58
+ message: 'Please provide a phone number in the query parameter: ?number=447414848795'
59
+ });
 
 
60
  }
61
+
62
+ console.log(`📱 Fetching messages for number: ${number}`);
63
+
64
+ // Check if we're still logged in by checking for login indicators
65
+ const currentUrl = loggedInPage.url();
66
+ console.log(`Current page URL: ${currentUrl}`);
67
+
68
+ // Navigate to the specific info page using the same logged-in page
69
+ const url = `https://getsms.cc/info/${number}`;
70
+ await loggedInPage.goto(url, {
71
+ waitUntil: "networkidle2"
 
 
 
 
 
72
  });
73
+
74
+ // Verify we didn't get redirected to login page
75
+ const finalUrl = loggedInPage.url();
76
+ if (finalUrl.includes('/auth/login')) {
77
+ throw new Error('Session expired - redirected to login page');
78
  }
79
+
80
+ console.log(`✅ Successfully navigated to: ${finalUrl}`);
81
+
82
+ // Wait a moment for any dynamic content to load
83
+ await loggedInPage.waitForTimeout(2000);
84
+
85
+ // Check if we need to login (session expired)
86
+ const needsLogin = await loggedInPage.evaluate(() => {
87
+ // Check for "Login to view" text or similar indicators
88
+ const bodyText = document.body.textContent || '';
89
+ return bodyText.includes('Login to view') ||
90
+ bodyText.includes('Please login') ||
91
+ bodyText.includes('You need to login') ||
92
+ document.querySelector('.login-required') !== null;
 
 
 
 
 
 
 
 
 
 
 
 
93
  });
94
+
95
+ if (needsLogin) {
96
+ console.log('🔄 Session expired, re-logging in...');
 
 
 
 
 
 
97
 
98
+ // Re-login process
99
+ await loggedInPage.goto("https://getsms.cc/auth/login", {
100
+ waitUntil: "networkidle2"
101
  });
 
 
 
 
 
 
 
 
 
102
 
103
+ // Clear any existing form data and re-enter credentials
104
+ await loggedInPage.evaluate(() => {
105
+ const emailInput = document.querySelector('#email');
106
+ const passwordInput = document.querySelector('#password');
107
+ if (emailInput) emailInput.value = '';
108
+ if (passwordInput) passwordInput.value = '';
109
+ });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
110
 
111
+ await loggedInPage.type("#email", "your@email.com", { delay: 50 });
112
+ await loggedInPage.type("#password", "yourpassword", { delay: 50 });
113
+
114
+ await Promise.all([
115
+ loggedInPage.click("input[type=submit]"),
116
+ loggedInPage.waitForNavigation({ waitUntil: "networkidle2" })
117
+ ]);
118
+
119
+ console.log("✅ Re-logged in successfully!");
120
+
121
+ // Navigate back to the number page
122
+ await loggedInPage.goto(url, {
123
+ waitUntil: "networkidle2"
124
+ });
125
+
126
+ // Wait for content to load
127
+ await loggedInPage.waitForTimeout(2000);
128
+ }
129
+
130
+ // Extract the last 3 messages
131
+ const lastMessages = await loggedInPage.evaluate(() => {
132
+ const messageElements = document.querySelectorAll('.direct-chat-msg');
 
 
 
 
 
 
133
 
134
+ // Double-check we're not seeing login messages
135
+ const bodyText = document.body.textContent || '';
136
+ if (bodyText.includes('Login to view')) {
137
+ return []; // Return empty array if still showing login message
 
 
138
  }
139
+
140
+ const messages = Array.from(messageElements).map(msg => {
141
+ const nameElement = msg.querySelector('.direct-chat-name');
142
+ const timeElement = msg.querySelector('.direct-chat-timestamp');
143
+ const textElement = msg.querySelector('.direct-chat-text');
144
+
145
+ // Skip ads/empty messages
146
+ const text = textElement?.textContent?.trim() || '';
147
+ if (text.includes('adsbygoogle') || text === '' || text.includes('Login to view')) {
148
+ return null;
149
+ }
150
+
151
+ return {
152
+ sender: nameElement?.textContent?.trim() || 'Unknown',
153
+ time: timeElement?.textContent?.trim() || 'Unknown time',
154
+ message: text
155
+ };
156
+ }).filter(msg => msg !== null); // Remove null entries (ads)
157
+
158
+ // Return last 3 messages
159
+ return messages.slice(-3);
160
  });
 
 
 
 
 
 
 
 
 
161
 
162
+ // Check if we got empty results due to login requirement
163
+ if (lastMessages.length === 0) {
164
+ const pageContent = await loggedInPage.evaluate(() => document.body.textContent);
165
+ if (pageContent.includes('Login to view')) {
166
+ throw new Error('Session expired and re-login failed - still showing "Login to view"');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
167
  }
168
+ }
 
 
 
 
 
 
 
 
 
 
169
 
170
+ console.log(`✅ Found ${lastMessages.length} messages for ${number}`);
171
+
172
+ // Return the response
 
 
173
  res.json({
174
+ success: true,
175
+ number: number,
176
+ timestamp: new Date().toISOString(),
177
+ messageCount: lastMessages.length,
178
+ messages: lastMessages
179
  });
 
 
 
 
 
180
 
181
+ } catch (error) {
182
+ console.error(`❌ Error fetching messages for ${req.query.number}:`, error);
183
+ res.status(500).json({
184
+ success: false,
185
+ error: 'Failed to fetch messages',
186
+ message: error.message
 
 
 
187
  });
 
 
 
188
  }
189
  });
190
 
191
+ // Health check endpoint
192
+ app.get('/api/health', (req, res) => {
193
+ res.json({
194
+ status: 'OK',
195
+ message: 'GetSMS API is running',
196
+ timestamp: new Date().toISOString(),
197
+ browserStatus: browser ? 'Connected' : 'Disconnected'
198
+ });
199
+ });
200
+
201
+ // Get available endpoints
202
+ app.get('/', (req, res) => {
203
+ res.json({
204
+ message: 'GetSMS Message Extraction API',
205
+ endpoints: {
206
+ 'GET /api/messages?number={phone_number}': 'Get last 3 messages for a phone number',
207
+ 'GET /api/health': 'Check API health status',
208
+ 'GET /': 'This help page'
209
+ },
210
+ example: {
211
+ url: '/api/messages?number=447414848795',
212
+ description: 'Get messages for phone number 447414848795'
213
+ }
214
+ });
215
+ });
216
+
217
  // Graceful shutdown
218
  process.on('SIGINT', async () => {
219
+ console.log('\n🔄 Shutting down gracefully...');
 
 
 
220
  if (browser) {
221
  await browser.close();
222
  }
 
224
  });
225
 
226
  process.on('SIGTERM', async () => {
227
+ console.log('\n🔄 Shutting down gracefully...');
 
 
 
228
  if (browser) {
229
  await browser.close();
230
  }
 
232
  });
233
 
234
  // Start server
235
+ async function startServer() {
236
+ try {
237
+ await initializeBrowser();
238
+
239
+ app.listen(PORT, () => {
240
+ console.log(`\n🌟 GetSMS API Server running on port ${PORT}`);
241
+ console.log(`📋 Available endpoints:`);
242
+ console.log(` GET http://localhost:${PORT}/api/messages?number=447414848795`);
243
+ console.log(` GET http://localhost:${PORT}/api/health`);
244
+ console.log(` GET http://localhost:${PORT}/`);
245
+ });
246
+ } catch (error) {
247
+ console.error('❌ Failed to start server:', error);
248
+ process.exit(1);
249
+ }
250
+ }
251
+
252
+ // Start the server
253
+ startServer();