|
|
import json
|
|
|
import random
|
|
|
|
|
|
from fastapi import Request, HTTPException
|
|
|
from fastapi.responses import StreamingResponse, Response
|
|
|
from starlette.background import BackgroundTask
|
|
|
|
|
|
from chatgpt.authorization import verify_token, get_req_token, get_ua
|
|
|
from utils.Client import Client
|
|
|
from utils.config import chatgpt_base_url_list, proxy_url_list, enable_gateway
|
|
|
|
|
|
headers_reject_list = [
|
|
|
"x-real-ip",
|
|
|
"x-forwarded-for",
|
|
|
"x-forwarded-proto",
|
|
|
"x-forwarded-port",
|
|
|
"x-forwarded-host",
|
|
|
"x-forwarded-server",
|
|
|
"cf-warp-tag-id",
|
|
|
"cf-visitor",
|
|
|
"cf-ray",
|
|
|
"cf-connecting-ip",
|
|
|
"cf-ipcountry",
|
|
|
"cdn-loop",
|
|
|
"remote-host",
|
|
|
"x-frame-options",
|
|
|
"x-xss-protection",
|
|
|
"x-content-type-options",
|
|
|
"content-security-policy",
|
|
|
"host",
|
|
|
"cookie",
|
|
|
"connection",
|
|
|
"content-length",
|
|
|
"content-encoding",
|
|
|
"x-middleware-prefetch",
|
|
|
"x-nextjs-data",
|
|
|
"purpose",
|
|
|
"x-forwarded-uri",
|
|
|
"x-forwarded-path",
|
|
|
"x-forwarded-method",
|
|
|
"x-forwarded-protocol",
|
|
|
"x-forwarded-scheme",
|
|
|
"cf-request-id",
|
|
|
"cf-worker",
|
|
|
"cf-access-client-id",
|
|
|
"cf-access-client-device-type",
|
|
|
"cf-access-client-device-model",
|
|
|
"cf-access-client-device-name",
|
|
|
"cf-access-client-device-brand",
|
|
|
"x-middleware-prefetch",
|
|
|
"x-forwarded-for",
|
|
|
"x-forwarded-host",
|
|
|
"x-forwarded-proto",
|
|
|
"x-forwarded-server",
|
|
|
"x-real-ip",
|
|
|
"x-forwarded-port",
|
|
|
"cf-connecting-ip",
|
|
|
"cf-ipcountry",
|
|
|
"cf-ray",
|
|
|
"cf-visitor",
|
|
|
]
|
|
|
|
|
|
|
|
|
async def get_real_req_token(token):
|
|
|
req_token = get_req_token(token)
|
|
|
if len(req_token) == 45 or req_token.startswith("eyJhbGciOi"):
|
|
|
return req_token
|
|
|
else:
|
|
|
req_token = get_req_token(None, token)
|
|
|
return req_token
|
|
|
|
|
|
|
|
|
async def chatgpt_reverse_proxy(request: Request, path: str):
|
|
|
try:
|
|
|
origin_host = request.url.netloc
|
|
|
if request.url.is_secure:
|
|
|
petrol = "https"
|
|
|
else:
|
|
|
petrol = "http"
|
|
|
if "x-forwarded-proto" in request.headers:
|
|
|
petrol = request.headers["x-forwarded-proto"]
|
|
|
if "cf-visitor" in request.headers:
|
|
|
cf_visitor = json.loads(request.headers["cf-visitor"])
|
|
|
petrol = cf_visitor.get("scheme", petrol)
|
|
|
|
|
|
params = dict(request.query_params)
|
|
|
request_cookies = dict(request.cookies)
|
|
|
|
|
|
headers = {
|
|
|
key: value for key, value in request.headers.items()
|
|
|
if (key.lower() not in ["host", "origin", "referer", "priority", "oai-device-id"] and key.lower() not in headers_reject_list)
|
|
|
}
|
|
|
|
|
|
base_url = random.choice(chatgpt_base_url_list) if chatgpt_base_url_list else "https://chatgpt.com"
|
|
|
if "assets/" in path:
|
|
|
base_url = "https://cdn.oaistatic.com"
|
|
|
if "file-" in path and "backend-api" not in path:
|
|
|
base_url = "https://files.oaiusercontent.com"
|
|
|
|
|
|
token = request.cookies.get("token")
|
|
|
req_token = await get_real_req_token(token)
|
|
|
ua = get_ua(req_token)
|
|
|
headers.update(ua)
|
|
|
|
|
|
headers.update({
|
|
|
"accept-language": "en-US,en;q=0.9",
|
|
|
"host": base_url.replace("https://", "").replace("http://", ""),
|
|
|
"origin": base_url,
|
|
|
"referer": f"{base_url}/"
|
|
|
})
|
|
|
|
|
|
token = headers.get("authorization", "").replace("Bearer ", "")
|
|
|
if token:
|
|
|
req_token = await get_real_req_token(token)
|
|
|
access_token = await verify_token(req_token)
|
|
|
headers.update({"authorization": access_token})
|
|
|
|
|
|
data = await request.body()
|
|
|
|
|
|
client = Client(proxy=random.choice(proxy_url_list) if proxy_url_list else None)
|
|
|
try:
|
|
|
background = BackgroundTask(client.close)
|
|
|
r = await client.request(request.method, f"{base_url}/{path}", params=params, headers=headers,
|
|
|
cookies=request_cookies, data=data, stream=True, allow_redirects=False)
|
|
|
|
|
|
if r.status_code == 302:
|
|
|
return Response(status_code=302,
|
|
|
headers={"Location": r.headers.get("Location").replace("chatgpt.com", origin_host)
|
|
|
.replace("cdn.oaistatic.com", origin_host)
|
|
|
.replace("https", petrol)}, background=background)
|
|
|
elif 'stream' in r.headers.get("content-type", ""):
|
|
|
return StreamingResponse(r.aiter_content(), media_type=r.headers.get("content-type", ""),
|
|
|
background=background)
|
|
|
else:
|
|
|
if "/backend-api/conversation" in path or "/register-websocket" in path:
|
|
|
response = Response(content=(await r.atext()), media_type=r.headers.get("content-type"),
|
|
|
status_code=r.status_code, background=background)
|
|
|
else:
|
|
|
content = ((await r.atext()).replace("chatgpt.com", origin_host)
|
|
|
.replace("cdn.oaistatic.com", origin_host)
|
|
|
|
|
|
.replace("https", petrol))
|
|
|
rheaders = dict(r.headers)
|
|
|
content_type = rheaders.get("content-type", "")
|
|
|
cache_control = rheaders.get("cache-control", "")
|
|
|
expires = rheaders.get("expires", "")
|
|
|
rheaders = {
|
|
|
"cache-control": cache_control,
|
|
|
"content-type": content_type,
|
|
|
"expires": expires
|
|
|
}
|
|
|
response = Response(content=content, headers=rheaders,
|
|
|
status_code=r.status_code, background=background)
|
|
|
return response
|
|
|
except Exception:
|
|
|
await client.close()
|
|
|
|
|
|
except Exception as e:
|
|
|
raise HTTPException(status_code=500, detail=str(e))
|
|
|
|