feat: Some quality of life improvements

This commit is contained in:
2026-04-17 17:18:24 +02:00
parent b1ff10916b
commit 1559ad1d2f
13 changed files with 318 additions and 232 deletions

View File

@@ -1,9 +1,10 @@
FROM python:3.12-slim
RUN pip install --no-cache-dir setuptools selenium websockets
WORKDIR /app
COPY main.py .
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD ["python", "main.py"]

0
proxy/__init__.py Normal file
View File

11
proxy/config.py Normal file
View File

@@ -0,0 +1,11 @@
import os
TARGET_URL = os.getenv("TARGET_URL", "https://omegleweb.io/")
TARGET_WS_URL = os.getenv(
"TARGET_WS_URL", "wss://omegleweb.io:8443/socket.io/?EIO=4&transport=websocket"
)
LOCAL_HOST = os.getenv("LOCAL_HOST", "0.0.0.0")
LOCAL_PORT = int(os.getenv("LOCAL_PORT", "8765"))
HEADLESS = os.getenv("HEADLESS", "false").lower() in ("true", "1", "yes")
CF_WAIT_TIME = int(os.getenv("CF_WAIT_TIME", "60"))
SELENIUM_URL = os.getenv("SELENIUM_URL", "http://localhost:4444")

View File

@@ -1,182 +1,24 @@
import os
import time
import asyncio
import logging
import websockets
from datetime import datetime
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
TARGET_URL = os.getenv("TARGET_URL", "https://omegleweb.io/")
TARGET_WS_URL = os.getenv("TARGET_WS_URL", "wss://omegleweb.io:8443/socket.io/?EIO=4&transport=websocket")
LOCAL_HOST = os.getenv("LOCAL_HOST", "0.0.0.0")
LOCAL_PORT = int(os.getenv("LOCAL_PORT", "8765"))
HEADLESS = os.getenv("HEADLESS", "false").lower() in ("true", "1", "yes")
CF_WAIT_TIME = int(os.getenv("CF_WAIT_TIME", "60"))
SELENIUM_URL = os.getenv("SELENIUM_URL", "http://localhost:4444")
from config import LOCAL_HOST, LOCAL_PORT
from websocket_client import handle_connection
credentials = {
"user_agent": None,
"cookies": None
}
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s [%(levelname)s] %(message)s",
datefmt="%H:%M:%S",
)
def stealth_js(driver):
driver.execute_script("""
Object.defineProperty(navigator, 'webdriver', {get: () => undefined});
Object.defineProperty(navigator, 'plugins', {get: () => [1, 2, 3, 4, 5]});
Object.defineProperty(navigator, 'languages', {get: () => ['en-US', 'en']});
window.chrome = {runtime: {}};
const originalQuery = window.navigator.permissions.query;
window.navigator.permissions.query = (parameters) => (
parameters.name === 'notifications' ?
Promise.resolve({state: Notification.permission}) :
originalQuery(parameters)
);
Object.defineProperty(navigator, 'permissions', {get: () => window.navigator.permissions});
""")
def extract_credentials():
print("\n" + "="*50)
print("[*] PHASE 1: SELENIUM EXTRACTION")
print("="*50)
print("[*] Launching Chrome browser...")
async def main():
await websockets.serve(handle_connection, LOCAL_HOST, LOCAL_PORT)
await asyncio.Future()
options = Options()
if HEADLESS:
options.add_argument("--headless=new")
options.add_argument("--no-sandbox")
options.add_argument("--disable-dev-shm-usage")
options.add_argument("--disable-gpu")
options.add_argument("--disable-software-rasterizer")
options.add_argument("--disable-extensions")
options.add_argument("--disable-blink-features=AutomationControlled")
options.add_argument("--disable-setuid-sandbox")
options.add_argument("--disable-background-networking")
options.add_argument("--disable-default-apps")
options.add_argument("--disable-sync")
options.add_argument("--disable-translate")
options.add_argument("--metrics-recording-only")
options.add_argument("--mute-audio")
options.add_argument("--no-first-run")
options.add_argument("--safebrowsing-disable-auto-update")
options.add_argument("--ignore-certificate-errors")
options.add_argument("--ignore-ssl-errors")
options.add_argument("--user-data-dir=/tmp/chrome-data")
options.add_argument("--disable-features=IsolateOrigins,site-per-process")
driver = webdriver.Remote(
command_executor=SELENIUM_URL + "/wd/hub",
options=options
)
stealth_js(driver)
if __name__ == "__main__":
try:
print("[*] Navigating to OmegleWeb homepage...")
driver.get(TARGET_URL)
wait = WebDriverWait(driver, CF_WAIT_TIME)
wait.until(EC.presence_of_element_located((By.ID, "logo")))
print("[*] Time's up! Extracting the goods...")
user_agent = driver.execute_script("return navigator.userAgent;")
selenium_cookies = driver.get_cookies()
cookie_string = "; ".join([f"{c['name']}={c['value']}" for c in selenium_cookies])
credentials["user_agent"] = user_agent
credentials["cookies"] = cookie_string
print("[+] Extraction successful!")
return True
except Exception as e:
print(f"[!] Extraction failed: {e}")
return False
finally:
print("[*] Closing browser...")
driver.quit()
async def start_bridge():
async def bridge_handler(local_client):
print(f"\n[{datetime.now().strftime('%H:%M:%S')}] [+] Local client connected to the bridge!")
while True:
headers = {
"User-Agent": credentials["user_agent"],
"Cookie": credentials["cookies"]
}
try:
print(f"[*] Attempting tunnel to OmegleWeb...")
async with websockets.connect(TARGET_WS_URL, additional_headers=headers) as target_server:
print("[+] Tunnel established! Relaying messages...")
async def forward_local_to_target():
async for message in local_client:
print(f"[{datetime.now().strftime('%H:%M:%S.%f')[:-3]}] [Local -> Omegle]: {message}")
await target_server.send(message)
async def forward_target_to_local():
async for message in target_server:
print(f"[{datetime.now().strftime('%H:%M:%S.%f')[:-3]}] [Omegle -> Local]: {message}")
await local_client.send(message)
t1 = asyncio.create_task(forward_local_to_target())
t2 = asyncio.create_task(forward_target_to_local())
done, pending = await asyncio.wait(
[t1, t2],
return_when=asyncio.FIRST_COMPLETED
)
for task in pending:
task.cancel()
if t1 in done and t1.exception() is None:
print("[-] Local client disconnected.")
break
print("[-] OmegleWeb connection closed.")
break
except websockets.exceptions.InvalidStatusCode as e:
if e.status_code == 403:
print(f"[!] HTTP 403 Forbidden: Cookies likely expired. Refreshing...")
loop = asyncio.get_running_loop()
success = await loop.run_in_executor(None, extract_credentials)
if not success:
print("[!] Failed to refresh cookies. Retrying in 5s...")
await asyncio.sleep(5)
continue
else:
print(f"[!] Bridge error (Status {e.status_code}): {e}")
break
except websockets.exceptions.ConnectionClosed:
print("[-] OmegleWeb disconnected.")
break
except Exception as e:
print(f"[!] Bridge error: {type(e).__name__}: {e}")
break
print(f"[*] Starting local WebSocket proxy on ws://{LOCAL_HOST}:{LOCAL_PORT}")
async with websockets.serve(bridge_handler, LOCAL_HOST, LOCAL_PORT):
await asyncio.Future()
def main():
if not extract_credentials():
print("[!] Initial extraction failed. Exiting.")
return
print("\n" + "="*50)
print("[*] PHASE 2: LAUNCH THE WEBSOCKET PROXY")
print("="*50)
try:
asyncio.run(start_bridge())
asyncio.run(main())
except KeyboardInterrupt:
print("\n[*] Shutting down...")
if __name__ == '__main__':
main()
logging.info("Shutting down...")

2
proxy/requirements.txt Normal file
View File

@@ -0,0 +1,2 @@
selenium==4.43.0
websockets==16.0

86
proxy/selenium_utils.py Normal file
View File

@@ -0,0 +1,86 @@
import logging
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from config import HEADLESS, CF_WAIT_TIME, SELENIUM_URL, TARGET_URL
log = logging.getLogger(__name__)
def get_chrome_options() -> Options:
options = Options()
if HEADLESS:
options.add_argument("--headless=new")
options.add_argument("--no-sandbox")
options.add_argument("--disable-dev-shm-usage")
options.add_argument("--disable-gpu")
options.add_argument("--disable-software-rasterizer")
options.add_argument("--disable-extensions")
options.add_argument("--disable-blink-features=AutomationControlled")
options.add_argument("--disable-setuid-sandbox")
options.add_argument("--disable-background-networking")
options.add_argument("--disable-default-apps")
options.add_argument("--disable-sync")
options.add_argument("--disable-translate")
options.add_argument("--metrics-recording-only")
options.add_argument("--mute-audio")
options.add_argument("--no-first-run")
options.add_argument("--safebrowsing-disable-auto-update")
options.add_argument("--ignore-certificate-errors")
options.add_argument("--ignore-ssl-errors")
options.add_argument("--user-data-dir=/tmp/chrome-data")
options.add_argument("--disable-features=IsolateOrigins,site-per-process")
return options
def apply_stealth_scripts(driver: webdriver.Remote) -> None:
driver.execute_script("""
Object.defineProperty(navigator, 'webdriver', {get: () => undefined});
Object.defineProperty(navigator, 'plugins', {get: () => [1, 2, 3, 4, 5]});
Object.defineProperty(navigator, 'languages', {get: () => ['en-US', 'en']});
window.chrome = {runtime: {}};
const originalQuery = window.navigator.permissions.query;
window.navigator.permissions.query = (parameters) => (
parameters.name === 'notifications'
? Promise.resolve({state: Notification.permission})
: originalQuery(parameters)
);
Object.defineProperty(navigator, 'permissions', {get: () => window.navigator.permissions});
""")
def fetch_fresh_credentials() -> tuple[str, str] | None:
log.info("Starting Selenium to fetch fresh credentials...")
driver = None
try:
driver = webdriver.Remote(
command_executor=f"{SELENIUM_URL}/wd/hub",
options=get_chrome_options(),
)
apply_stealth_scripts(driver)
driver.get(TARGET_URL)
wait = WebDriverWait(driver, CF_WAIT_TIME)
wait.until(EC.presence_of_element_located((By.ID, "logo")))
user_agent = driver.execute_script("return navigator.userAgent;")
selenium_cookies = driver.get_cookies()
cookies = "; ".join(
f"{c['name']}={c['value']}"
for c in selenium_cookies
)
log.info("Successfully extracted credentials via Selenium")
return (user_agent, cookies)
except Exception as e:
log.error(f"Failed to extract credentials: {e}")
return None
finally:
if driver is not None:
driver.quit()

85
proxy/websocket_client.py Normal file
View File

@@ -0,0 +1,85 @@
import asyncio
import logging
import websockets
from config import TARGET_WS_URL, LOCAL_HOST, LOCAL_PORT
from selenium_utils import fetch_fresh_credentials
log = logging.getLogger(__name__)
async def handle_connection(local_client):
log.info("Local client connected, fetching credentials...")
result = await asyncio.get_running_loop().run_in_executor(
None, fetch_fresh_credentials
)
if result is None:
log.error("Could not fetch credentials")
await local_client.close(1011, "Failed to bypass Cloudflare")
return
user_agent, cookies = result
headers = {
"User-Agent": user_agent,
"Cookie": cookies,
}
try:
log.info("Connecting to OmegleWeb...")
async with websockets.connect(
TARGET_WS_URL,
additional_headers=headers,
) as target_server:
log.info("OmegleWeb connected! Notifying client...")
await local_client.send("SUCCESS")
log.info("Starting relay")
await relay_bidirectional(local_client, target_server)
except websockets.exceptions.InvalidStatusCode as e:
log.error(f"Omegle connection failed (Status {e.status_code})")
await local_client.close(1011, f"Connection failed: {e.status_code}")
except websockets.exceptions.ConnectionClosed:
log.info("OmegleWeb disconnected")
except Exception as e:
log.error(f"Connection error: {type(e).__name__}: {e}")
await local_client.close(1011, str(e))
async def relay_bidirectional(local_ws, target_ws):
async def forward_local():
try:
async for message in local_ws:
log.debug(f"[Local -> Omegle]: {message}")
await target_ws.send(message)
except websockets.exceptions.ConnectionClosed:
log.info("Local client disconnected")
except Exception as e:
log.error(f"Forward local error: {e}")
async def forward_remote():
try:
async for message in target_ws:
log.debug(f"[Omegle -> Local]: {message}")
await local_ws.send(message)
except websockets.exceptions.ConnectionClosed:
log.info("OmegleWeb disconnected")
except Exception as e:
log.error(f"Forward remote error: {e}")
await asyncio.gather(
forward_local(),
forward_remote(),
)
async def main():
log.info(f"Starting WebSocket proxy on ws://{LOCAL_HOST}:{LOCAL_PORT}")
await websockets.serve(handle_connection, LOCAL_HOST, LOCAL_PORT)
await asyncio.Future()
if __name__ == "__main__":
asyncio.run(main())