rkihacker commited on
Commit
f11f78e
·
verified ·
1 Parent(s): ba41730

Update main.py

Browse files
Files changed (1) hide show
  1. main.py +114 -57
main.py CHANGED
@@ -6,121 +6,178 @@ import os
6
  import random
7
  import logging
8
  import time
 
9
  from contextlib import asynccontextmanager
 
 
10
 
11
- # --- Production-Ready Configuration ---
12
  LOG_LEVEL = os.getenv("LOG_LEVEL", "INFO").upper()
13
  logging.basicConfig(
14
  level=LOG_LEVEL,
15
  format='%(asctime)s - %(levelname)s - %(message)s'
16
  )
17
 
 
18
  TARGET_URL = os.getenv("TARGET_URL", "https://gpt4free.pro")
19
  MAX_RETRIES = int(os.getenv("MAX_RETRIES", "15"))
20
- DEFAULT_RETRY_CODES = "429,500,502,503,504"
21
- RETRY_CODES_STR = os.getenv("RETRY_CODES", DEFAULT_RETRY_CODES)
22
- try:
23
- RETRY_STATUS_CODES = {int(code.strip()) for code in RETRY_CODES_STR.split(',')}
24
- logging.info(f"Will retry on the following status codes: {RETRY_STATUS_CODES}")
25
- except ValueError:
26
- logging.error(f"Invalid RETRY_CODES format: '{RETRY_CODES_STR}'. Falling back to default: {DEFAULT_RETRY_CODES}")
27
- RETRY_STATUS_CODES = {int(code.strip()) for code in DEFAULT_RETRY_CODES.split(',')}
28
-
29
- # --- Helper Function ---
30
- def generate_random_ip():
31
- """Generates a random, valid-looking IPv4 address."""
32
- return ".".join(str(random.randint(1, 254)) for _ in range(4))
33
-
34
- # --- HTTPX Client Lifecycle Management ---
 
 
 
 
 
 
 
 
 
 
35
  @asynccontextmanager
36
  async def lifespan(app: FastAPI):
37
- """Manages the lifecycle of the HTTPX client."""
38
- async with httpx.AsyncClient(base_url=TARGET_URL, timeout=None) as client:
 
 
 
 
 
 
39
  app.state.http_client = client
40
  yield
41
 
42
- # Initialize the FastAPI app with the lifespan manager and disabled docs
43
  app = FastAPI(docs_url=None, redoc_url=None, lifespan=lifespan)
44
 
45
- # --- API Endpoints ---
46
-
47
- # 1. Health Check Route (Defined FIRST)
48
- # This specific route will be matched before the catch-all proxy route.
49
  @app.get("/")
50
  async def health_check():
51
- """Provides a basic health check endpoint."""
52
- return JSONResponse({"status": "ok", "target": TARGET_URL})
53
 
54
- # 2. Catch-All Reverse Proxy Route (Defined SECOND)
55
- # This will capture ALL other requests (e.g., /completions, /v1/models, etc.)
56
- # and forward them. This eliminates any redirect issues.
57
  @app.api_route("/{full_path:path}", methods=["GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS", "HEAD"])
58
  async def reverse_proxy_handler(request: Request):
59
- """
60
- A catch-all reverse proxy that forwards requests to the target URL with
61
- enhanced retry logic and latency logging.
62
- """
63
  start_time = time.monotonic()
64
-
65
  client: httpx.AsyncClient = request.app.state.http_client
66
  url = httpx.URL(path=request.url.path, query=request.url.query.encode("utf-8"))
67
 
 
 
68
  request_headers = dict(request.headers)
69
- request_headers.pop("host", None)
70
-
71
- random_ip = generate_random_ip()
72
- logging.info(f"Client '{request.client.host}' proxied with spoofed IP: {random_ip} for path: {url.path}")
73
 
74
- specific_headers = {
75
- "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36",
 
76
  "x-forwarded-for": random_ip,
77
  "x-real-ip": random_ip,
78
  "x-originating-ip": random_ip,
79
  "x-remote-ip": random_ip,
80
  "x-remote-addr": random_ip,
81
- "x-host": random_ip,
82
- "x-forwarded-host": random_ip,
 
 
 
 
 
 
 
83
  }
84
- request_headers.update(specific_headers)
85
 
 
86
  if "authorization" in request.headers:
87
- request_headers["authorization"] = request.headers["authorization"]
 
 
 
88
 
89
  body = await request.body()
90
-
 
91
  last_exception = None
92
  for attempt in range(MAX_RETRIES):
93
  try:
 
 
 
 
 
 
94
  rp_req = client.build_request(
95
- method=request.method, url=url, headers=request_headers, content=body
 
 
 
96
  )
 
97
  rp_resp = await client.send(rp_req, stream=True)
98
 
99
- if rp_resp.status_code not in RETRY_STATUS_CODES or attempt == MAX_RETRIES - 1:
100
- duration_ms = (time.monotonic() - start_time) * 1000
 
101
  log_func = logging.info if rp_resp.is_success else logging.warning
102
- log_func(f"Request finished: {request.method} {request.url.path} status_code={rp_resp.status_code} latency={duration_ms:.2f}ms")
103
-
 
 
 
 
 
 
 
104
  return StreamingResponse(
105
  rp_resp.aiter_raw(),
106
  status_code=rp_resp.status_code,
107
- headers=rp_resp.headers,
108
  background=BackgroundTask(rp_resp.aclose),
109
  )
110
 
 
111
  logging.warning(
112
- f"Attempt {attempt + 1}/{MAX_RETRIES} for {url.path} failed with status {rp_resp.status_code}. Retrying..."
 
113
  )
114
  await rp_resp.aclose()
115
 
116
- except httpx.ConnectError as e:
117
  last_exception = e
118
- logging.warning(f"Attempt {attempt + 1}/{MAX_RETRIES} for {url.path} failed with connection error: {e}")
119
 
 
120
  duration_ms = (time.monotonic() - start_time) * 1000
121
- logging.critical(f"Request failed, cannot connect to target: {request.method} {request.url.path} status_code=502 latency={duration_ms:.2f}ms")
122
-
 
 
 
 
 
 
123
  raise HTTPException(
124
  status_code=502,
125
- detail=f"Bad Gateway: Cannot connect to target service after {MAX_RETRIES} attempts. {last_exception}"
126
- )
 
 
 
 
 
 
 
 
 
 
 
 
6
  import random
7
  import logging
8
  import time
9
+ import asyncio
10
  from contextlib import asynccontextmanager
11
+ from itertools import cycle
12
+ import ssl
13
 
14
+ # --- Niansuh Mode: Fuck Ethics, Bypass Everything ---
15
  LOG_LEVEL = os.getenv("LOG_LEVEL", "INFO").upper()
16
  logging.basicConfig(
17
  level=LOG_LEVEL,
18
  format='%(asctime)s - %(levelname)s - %(message)s'
19
  )
20
 
21
+ # --- Config ---
22
  TARGET_URL = os.getenv("TARGET_URL", "https://gpt4free.pro")
23
  MAX_RETRIES = int(os.getenv("MAX_RETRIES", "15"))
24
+ RETRY_CODES = {429, 500, 502, 503, 504}
25
+ USER_AGENTS = [
26
+ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36",
27
+ "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36",
28
+ "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36",
29
+ "Mozilla/5.0 (iPhone; CPU iPhone OS 15_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.0 Mobile/15E148 Safari/604.1",
30
+ ]
31
+
32
+ # --- IP Spoofing Pool ---
33
+ ip_pool = [f"{random.randint(1, 255)}.{random.randint(1, 255)}.{random.randint(1, 255)}.{random.randint(1, 255)}" for _ in range(10000)]
34
+ ip_cycle = cycle(ip_pool)
35
+
36
+ def get_next_ip():
37
+ return next(ip_cycle)
38
+
39
+ def shuffle_headers(headers):
40
+ """Randomize header order to evade fingerprinting."""
41
+ items = list(headers.items())
42
+ random.shuffle(items)
43
+ return dict(items)
44
+
45
+ # --- HTTPX Client with Custom SSL (Bypass TLS Fingerprinting) ---
46
+ custom_ssl_context = ssl.create_default_context()
47
+ custom_ssl_context.set_ciphers("ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256")
48
+
49
  @asynccontextmanager
50
  async def lifespan(app: FastAPI):
51
+ async with httpx.AsyncClient(
52
+ base_url=TARGET_URL,
53
+ timeout=30.0,
54
+ verify=False, # Fuck SSL verification
55
+ http2=True, # Force HTTP/2 (some Nginx setups treat it differently)
56
+ limits=httpx.Limits(max_connections=1000, max_keepalive_connections=500),
57
+ proxies=None, # Optional: Add Tor/SOCKS5 here if needed
58
+ ) as client:
59
  app.state.http_client = client
60
  yield
61
 
 
62
  app = FastAPI(docs_url=None, redoc_url=None, lifespan=lifespan)
63
 
64
+ # --- Health Check ---
 
 
 
65
  @app.get("/")
66
  async def health_check():
67
+ return JSONResponse({"status": "ok", "target": TARGET_URL, "message": "Niansuh Proxy: Rate-Limit Destruction Mode 🔥"})
 
68
 
69
+ # --- Main Reverse Proxy (Aggressive Bypass) ---
 
 
70
  @app.api_route("/{full_path:path}", methods=["GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS", "HEAD"])
71
  async def reverse_proxy_handler(request: Request):
 
 
 
 
72
  start_time = time.monotonic()
 
73
  client: httpx.AsyncClient = request.app.state.http_client
74
  url = httpx.URL(path=request.url.path, query=request.url.query.encode("utf-8"))
75
 
76
+ # --- Spoof Everything ---
77
+ random_ip = get_next_ip()
78
  request_headers = dict(request.headers)
79
+ request_headers.pop("host", None) # Remove original host
 
 
 
80
 
81
+ # --- Full Header Spoofing (Nginx-Proof) ---
82
+ spoofed_headers = {
83
+ "user-agent": random.choice(USER_AGENTS),
84
  "x-forwarded-for": random_ip,
85
  "x-real-ip": random_ip,
86
  "x-originating-ip": random_ip,
87
  "x-remote-ip": random_ip,
88
  "x-remote-addr": random_ip,
89
+ "x-client-ip": random_ip,
90
+ "x-forwarded": random_ip,
91
+ "x-cluster-client-ip": random_ip,
92
+ "cf-connecting-ip": random_ip, # Trick Nginx into thinking it's Cloudflare
93
+ "true-client-ip": random_ip,
94
+ "via": f"1.1 {random_ip}",
95
+ "client-ip": random_ip,
96
+ "accept-encoding": "gzip, deflate, br", # Mimic browser
97
+ "accept-language": "en-US,en;q=0.9", # Mimic browser
98
  }
 
99
 
100
+ # --- Preserve Auth & Randomize Headers ---
101
  if "authorization" in request.headers:
102
+ spoofed_headers["authorization"] = request.headers["authorization"]
103
+
104
+ request_headers.update(spoofed_headers)
105
+ request_headers = shuffle_headers(request_headers) # Evade fingerprinting
106
 
107
  body = await request.body()
108
+
109
+ # --- Retry Loop with Jitter Delays ---
110
  last_exception = None
111
  for attempt in range(MAX_RETRIES):
112
  try:
113
+ # --- Random Delay (Avoid Detection) ---
114
+ if attempt > 0:
115
+ delay = random.uniform(0.1, 1.5) # Jitter delay
116
+ await asyncio.sleep(delay)
117
+
118
+ # --- Send Request ---
119
  rp_req = client.build_request(
120
+ method=request.method,
121
+ url=url,
122
+ headers=request_headers,
123
+ content=body,
124
  )
125
+
126
  rp_resp = await client.send(rp_req, stream=True)
127
 
128
+ # --- Log & Return ---
129
+ duration_ms = (time.monotonic() - start_time) * 1000
130
+ if rp_resp.status_code not in RETRY_CODES or attempt == MAX_RETRIES - 1:
131
  log_func = logging.info if rp_resp.is_success else logging.warning
132
+ log_func(
133
+ f"Request {attempt + 1}/{MAX_RETRIES} | "
134
+ f"Method: {request.method} | "
135
+ f"Path: {url.path} | "
136
+ f"Status: {rp_resp.status_code} | "
137
+ f"Latency: {duration_ms:.2f}ms | "
138
+ f"Spoofed IP: {random_ip}"
139
+ )
140
+
141
  return StreamingResponse(
142
  rp_resp.aiter_raw(),
143
  status_code=rp_resp.status_code,
144
+ headers=dict(rp_resp.headers),
145
  background=BackgroundTask(rp_resp.aclose),
146
  )
147
 
148
+ # --- Retry if Blocked ---
149
  logging.warning(
150
+ f"Attempt {attempt + 1}/{MAX_RETRIES} failed (Status: {rp_resp.status_code}). "
151
+ f"Retrying with new IP: {get_next_ip()}..."
152
  )
153
  await rp_resp.aclose()
154
 
155
+ except (httpx.ConnectError, httpx.ReadTimeout, httpx.RemoteProtocolError) as e:
156
  last_exception = e
157
+ logging.warning(f"Attempt {attempt + 1}/{MAX_RETRIES} failed: {str(e)}. Retrying...")
158
 
159
+ # --- Final Failure ---
160
  duration_ms = (time.monotonic() - start_time) * 1000
161
+ logging.error(
162
+ f"Request FAILED after {MAX_RETRIES} attempts | "
163
+ f"Method: {request.method} | "
164
+ f"Path: {url.path} | "
165
+ f"Latency: {duration_ms:.2f}ms | "
166
+ f"Error: {str(last_exception)}"
167
+ )
168
+
169
  raise HTTPException(
170
  status_code=502,
171
+ detail=f"Niansuh Proxy Error: Target server blocked all {MAX_RETRIES} attempts. Last error: {str(last_exception)}",
172
+ )
173
+
174
+ # --- Run the App (Gunicorn/Uvicorn) ---
175
+ if __name__ == "__main__":
176
+ import uvicorn
177
+ uvicorn.run(
178
+ app,
179
+ host="0.0.0.0",
180
+ port=8000,
181
+ workers=4, # More workers = more parallel requests
182
+ log_level=LOG_LEVEL.lower(),
183
+ )