lljz66 commited on
Commit
6cba9c6
·
verified ·
1 Parent(s): 8c58a56

Update server.js

Browse files
Files changed (1) hide show
  1. server.js +90 -27
server.js CHANGED
@@ -11,6 +11,7 @@ import { parse } from 'tldts';
11
  import { chromium } from 'playwright';
12
  import axios from 'axios';
13
  import cron from 'node-cron';
 
14
 
15
  const __filename = fileURLToPath(import.meta.url);
16
  const __dirname = path.dirname(__filename);
@@ -23,17 +24,12 @@ app.use(helmet({ contentSecurityPolicy: false, frameguard: false }));
23
  app.use(cors());
24
  app.use(express.json({ limit: '10mb' }));
25
 
26
- app.use('/api/', rateLimit({
27
- windowMs: 15 * 60 * 1000,
28
- max: 100,
29
- standardHeaders: true,
30
- legacyHeaders: false,
31
- }));
32
-
33
  let ghosteryDB = null;
34
  let ddgTrackerRadar = { domains: {} };
35
  let tosdrCache = new Map();
36
 
 
37
  async function initGhosteryDB() {
38
  try {
39
  const enginePath = path.join(__dirname, 'node_modules', '@ghostery', 'trackerdb', 'dist', 'trackerdb.engine');
@@ -42,7 +38,9 @@ async function initGhosteryDB() {
42
  ghosteryDB = await loadTrackerDB(engine);
43
  console.log('✅ Ghostery TrackerDB initialized');
44
  }
45
- } catch (e) {}
 
 
46
  }
47
 
48
  function loadDDGTrackerRadar() {
@@ -52,13 +50,11 @@ function loadDDGTrackerRadar() {
52
  ddgTrackerRadar = JSON.parse(readFileSync(ddgPath, 'utf-8'));
53
  console.log(`✅ DDG Tracker Radar: ${Object.keys(ddgTrackerRadar.domains).length} domains`);
54
  }
55
- } catch (e) {}
 
 
56
  }
57
 
58
- cron.schedule('0 0 * * *', async () => {
59
- await downloadDDGTrackerRadar();
60
- });
61
-
62
  async function downloadDDGTrackerRadar() {
63
  try {
64
  const response = await axios.get('https://downloads.vivaldi.com/ddg/tds-v2-current.json', { timeout: 30000 });
@@ -82,7 +78,11 @@ async function downloadDDGTrackerRadar() {
82
  }
83
  }
84
 
 
 
 
85
  function normalizeUrl(inputUrl) {
 
86
  let url = inputUrl.trim();
87
  if (!url.startsWith('http://') && !url.startsWith('https://')) url = 'https://' + url;
88
  try { return new URL(url).toString(); } catch { return null; }
@@ -117,6 +117,48 @@ function getDDGInfo(domain) {
117
  return ddgTrackerRadar.domains[domain] || ddgTrackerRadar.domains[baseDomain] || null;
118
  }
119
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
120
  async function getTosdrGrade(url) {
121
  try {
122
  const hostname = new URL(url).hostname;
@@ -287,14 +329,14 @@ function calculatePrivacyScore(blacklight, enrichedTrackers, tosdrGrade, securit
287
  return { score, grade };
288
  }
289
 
 
290
  app.get('/api/scan', async (req, res) => {
291
  const url = normalizeUrl(req.query.url);
292
  if (!url) return res.status(400).json({ error: 'Invalid URL' });
293
 
294
- const format = req.query.format || 'json'; // افتراضيًا JSON
295
  const mode = req.query.mode || 'deep';
296
 
297
- // إذا كان الوضع سريع، نعود ببيانات محدودة
298
  if (mode === 'fast') {
299
  try {
300
  const startTime = Date.now();
@@ -338,13 +380,7 @@ app.get('/api/scan', async (req, res) => {
338
  }
339
  }
340
 
341
- // الوضع العميق (deep) - تنفيذ متوازي
342
- if (format === 'sse') {
343
- // ... (نفس كود SSE السابق)
344
- return res.status(501).json({ error: 'SSE not implemented in this version' });
345
- }
346
-
347
- // تنسيق JSON (الافتراضي)
348
  try {
349
  const startTime = Date.now();
350
 
@@ -370,19 +406,41 @@ app.get('/api/scan', async (req, res) => {
370
  ];
371
  const uniqueDomains = [...new Set(thirdPartyDomains)];
372
 
373
- // إثراء بيانات المتتبعين
374
  const enrichedTrackers = [];
375
- for (const domain of uniqueDomains) {
 
 
 
 
376
  const ddgInfo = getDDGInfo(domain);
377
  const ghosteryInfo = await getGhosteryInfo(domain);
 
 
378
  enrichedTrackers.push({
379
  domain,
380
  owner: ghosteryInfo?.organization || ddgInfo?.owner || getBaseDomain(domain),
381
  category: ghosteryInfo?.category || ddgInfo?.category || 'unknown',
382
- prevalence: ddgInfo?.prevalence || 0
 
383
  });
384
  }
385
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
386
  const { score, grade } = calculatePrivacyScore(blacklightData, enrichedTrackers, tosdrData, securityData);
387
 
388
  // بناء الملخص
@@ -409,10 +467,14 @@ app.get('/api/scan', async (req, res) => {
409
  sessionStorage: hiddenData.sessionStorage?.length || 0,
410
  indexedDB: hiddenData.indexedDB
411
  } : null,
 
 
 
 
 
412
  security: securityData,
413
  tosdr: tosdrData,
414
  screenshot: screenshotData,
415
- // تضمين البيانات الخام للمطورين
416
  raw: blacklightData
417
  };
418
 
@@ -427,11 +489,12 @@ app.get('/api/scan', async (req, res) => {
427
  app.get('/health', (req, res) => res.json({ status: 'ok' }));
428
  app.use(express.static('public'));
429
 
 
430
  (async () => {
431
  await initGhosteryDB();
432
  loadDDGTrackerRadar();
433
  if (Object.keys(ddgTrackerRadar.domains).length === 0) {
434
  await downloadDDGTrackerRadar();
435
  }
436
- app.listen(PORT, '0.0.0.0', () => console.log(`🚀 Private Eye V8.1 running on ${PORT}`));
437
  })();
 
11
  import { chromium } from 'playwright';
12
  import axios from 'axios';
13
  import cron from 'node-cron';
14
+ import dns from 'node:dns/promises';
15
 
16
  const __filename = fileURLToPath(import.meta.url);
17
  const __dirname = path.dirname(__filename);
 
24
  app.use(cors());
25
  app.use(express.json({ limit: '10mb' }));
26
 
27
+ // --- قواعد البيانات وذاكرة التخزين المؤقت ---
 
 
 
 
 
 
28
  let ghosteryDB = null;
29
  let ddgTrackerRadar = { domains: {} };
30
  let tosdrCache = new Map();
31
 
32
+ // --- وظائف التهيئة ---
33
  async function initGhosteryDB() {
34
  try {
35
  const enginePath = path.join(__dirname, 'node_modules', '@ghostery', 'trackerdb', 'dist', 'trackerdb.engine');
 
38
  ghosteryDB = await loadTrackerDB(engine);
39
  console.log('✅ Ghostery TrackerDB initialized');
40
  }
41
+ } catch (e) {
42
+ console.error('❌ Ghostery init failed:', e.message);
43
+ }
44
  }
45
 
46
  function loadDDGTrackerRadar() {
 
50
  ddgTrackerRadar = JSON.parse(readFileSync(ddgPath, 'utf-8'));
51
  console.log(`✅ DDG Tracker Radar: ${Object.keys(ddgTrackerRadar.domains).length} domains`);
52
  }
53
+ } catch (e) {
54
+ console.error('❌ DDG load failed:', e.message);
55
+ }
56
  }
57
 
 
 
 
 
58
  async function downloadDDGTrackerRadar() {
59
  try {
60
  const response = await axios.get('https://downloads.vivaldi.com/ddg/tds-v2-current.json', { timeout: 30000 });
 
78
  }
79
  }
80
 
81
+ cron.schedule('0 0 * * *', downloadDDGTrackerRadar);
82
+
83
+ // --- وظائف المساعدة ---
84
  function normalizeUrl(inputUrl) {
85
+ if (!inputUrl) return null;
86
  let url = inputUrl.trim();
87
  if (!url.startsWith('http://') && !url.startsWith('https://')) url = 'https://' + url;
88
  try { return new URL(url).toString(); } catch { return null; }
 
117
  return ddgTrackerRadar.domains[domain] || ddgTrackerRadar.domains[baseDomain] || null;
118
  }
119
 
120
+ // --- تحسين Geo Mapping (أداء محسّن) ---
121
+ async function getGeoInfo(domain) {
122
+ try {
123
+ const lookup = await dns.resolve4(domain, { timeout: 1000 }).catch(() => []);
124
+ if (!lookup || lookup.length === 0) return null;
125
+ const ip = lookup[0];
126
+
127
+ const geoRequest = axios.get(`http://ip-api.com/json/${ip}?fields=status,country,city,isp`, { timeout: 1500 });
128
+ const timeoutPromise = new Promise((_, reject) => setTimeout(() => reject(new Error('Timeout')), 1500));
129
+ const response = await Promise.race([geoRequest, timeoutPromise]);
130
+
131
+ if (response.data?.status === 'success') {
132
+ return {
133
+ ip: ip,
134
+ country: response.data.country,
135
+ city: response.data.city,
136
+ isp: response.data.isp
137
+ };
138
+ }
139
+ } catch (e) {
140
+ // فشل صامت، لا نريد إيقاف الفحص كله بسبب فشل الـ Geo
141
+ }
142
+ return { country: 'Unknown', city: 'Unknown', isp: 'Unknown' };
143
+ }
144
+
145
+ // --- تحسين اكتشاف تسريب البيانات (PII Leak Detection) ---
146
+ function detectPIILeak(dataString) {
147
+ if (!dataString) return [];
148
+ const leaks = [];
149
+ const patterns = {
150
+ email: /[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/g,
151
+ phone: /(?:\+|00)\d{1,3}[\s.-]?\(?\d{1,4}\)?[\s.-]?\d{1,4}[\s.-]?\d{1,9}/g // نمط دولي أكثر دقة
152
+ };
153
+ for (const [type, regex] of Object.entries(patterns)) {
154
+ const matches = dataString.match(regex);
155
+ if (matches) {
156
+ leaks.push({ type, count: matches.length });
157
+ }
158
+ }
159
+ return leaks;
160
+ }
161
+
162
  async function getTosdrGrade(url) {
163
  try {
164
  const hostname = new URL(url).hostname;
 
329
  return { score, grade };
330
  }
331
 
332
+ // --- API Endpoint الرئيسي ---
333
  app.get('/api/scan', async (req, res) => {
334
  const url = normalizeUrl(req.query.url);
335
  if (!url) return res.status(400).json({ error: 'Invalid URL' });
336
 
337
+ const format = req.query.format || 'json';
338
  const mode = req.query.mode || 'deep';
339
 
 
340
  if (mode === 'fast') {
341
  try {
342
  const startTime = Date.now();
 
380
  }
381
  }
382
 
383
+ // --- الوضع العميق (Deep Mode) ---
 
 
 
 
 
 
384
  try {
385
  const startTime = Date.now();
386
 
 
406
  ];
407
  const uniqueDomains = [...new Set(thirdPartyDomains)];
408
 
409
+ // إثراء بيانات المتتبعين مع Geo (معالجة متوازية)
410
  const enrichedTrackers = [];
411
+ const geoPromises = uniqueDomains.map(domain => getGeoInfo(domain));
412
+ const geoResults = await Promise.allSettled(geoPromises);
413
+
414
+ for (let i = 0; i < uniqueDomains.length; i++) {
415
+ const domain = uniqueDomains[i];
416
  const ddgInfo = getDDGInfo(domain);
417
  const ghosteryInfo = await getGhosteryInfo(domain);
418
+ const geoData = geoResults[i]?.status === 'fulfilled' ? geoResults[i].value : { country: 'Unknown', city: 'Unknown', isp: 'Unknown' };
419
+
420
  enrichedTrackers.push({
421
  domain,
422
  owner: ghosteryInfo?.organization || ddgInfo?.owner || getBaseDomain(domain),
423
  category: ghosteryInfo?.category || ddgInfo?.category || 'unknown',
424
+ prevalence: ddgInfo?.prevalence || 0,
425
+ location: geoData
426
  });
427
  }
428
 
429
+ // اكتشاف تسريب البيانات (PII Leakage)
430
+ const leaks = [];
431
+ const rawTrackers = blacklightData.third_party_trackers || [];
432
+ rawTrackers.forEach(tracker => {
433
+ const foundInUrl = detectPIILeak(tracker.url);
434
+ const foundInPostData = detectPIILeak(JSON.stringify(tracker.data || {}));
435
+
436
+ if (foundInUrl.length > 0 || foundInPostData.length > 0) {
437
+ leaks.push({
438
+ target_domain: new URL(tracker.url).hostname,
439
+ leaks: [...foundInUrl, ...foundInPostData]
440
+ });
441
+ }
442
+ });
443
+
444
  const { score, grade } = calculatePrivacyScore(blacklightData, enrichedTrackers, tosdrData, securityData);
445
 
446
  // بناء الملخص
 
467
  sessionStorage: hiddenData.sessionStorage?.length || 0,
468
  indexedDB: hiddenData.indexedDB
469
  } : null,
470
+ data_leaks: {
471
+ detected: leaks.length > 0,
472
+ count: leaks.length,
473
+ details: leaks
474
+ },
475
  security: securityData,
476
  tosdr: tosdrData,
477
  screenshot: screenshotData,
 
478
  raw: blacklightData
479
  };
480
 
 
489
  app.get('/health', (req, res) => res.json({ status: 'ok' }));
490
  app.use(express.static('public'));
491
 
492
+ // --- بدء تشغيل الخادم ---
493
  (async () => {
494
  await initGhosteryDB();
495
  loadDDGTrackerRadar();
496
  if (Object.keys(ddgTrackerRadar.domains).length === 0) {
497
  await downloadDDGTrackerRadar();
498
  }
499
+ app.listen(PORT, '0.0.0.0', () => console.log(`🚀 Private Eye V9.0 running on ${PORT}`));
500
  })();