har_file.py 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. from __future__ import annotations
  2. import base64
  3. import json
  4. import os
  5. import re
  6. import time
  7. import uuid
  8. import random
  9. from urllib.parse import unquote
  10. from copy import deepcopy
  11. from .crypt import decrypt, encrypt
  12. from ...requests import StreamSession
  13. from ...cookies import get_cookies_dir
  14. from ...errors import NoValidHarFileError
  15. from ... import debug
  16. arkose_url = "https://tcr9i.chat.openai.com/fc/gt2/public_key/35536E1E-65B4-4D96-9D97-6ADB7EFF8147"
  17. backend_url = "https://chatgpt.com/backend-api/conversation"
  18. backend_anon_url = "https://chatgpt.com/backend-anon/conversation"
  19. start_url = "https://chatgpt.com/"
  20. conversation_url = "https://chatgpt.com/c/"
  21. class RequestConfig:
  22. cookies: dict = None
  23. headers: dict = None
  24. access_token: str = None
  25. proof_token: list = None
  26. turnstile_token: str = None
  27. arkose_request: arkReq = None
  28. arkose_token: str = None
  29. headers: dict = {}
  30. cookies: dict = {}
  31. data_build: str = "prod-697873d7e78bb14df6e13af3a91fa237cc4db415"
  32. class arkReq:
  33. def __init__(self, arkURL, arkBx, arkHeader, arkBody, arkCookies, userAgent):
  34. self.arkURL = arkURL
  35. self.arkBx = arkBx
  36. self.arkHeader = arkHeader
  37. self.arkBody = arkBody
  38. self.arkCookies = arkCookies
  39. self.userAgent = userAgent
  40. def get_har_files():
  41. harPath = []
  42. for root, _, files in os.walk(get_cookies_dir()):
  43. for file in files:
  44. if file.endswith(".har"):
  45. harPath.append(os.path.join(root, file))
  46. if not harPath:
  47. raise NoValidHarFileError("No .har file found")
  48. harPath.sort(key=lambda x: os.path.getmtime(x))
  49. return harPath
  50. def readHAR():
  51. for path in get_har_files():
  52. with open(path, 'rb') as file:
  53. try:
  54. harFile = json.loads(file.read())
  55. except json.JSONDecodeError:
  56. # Error: not a HAR file!
  57. continue
  58. for v in harFile['log']['entries']:
  59. v_headers = get_headers(v)
  60. if arkose_url == v['request']['url']:
  61. RequestConfig.arkose_request = parseHAREntry(v)
  62. elif v['request']['url'].startswith(start_url):
  63. try:
  64. match = re.search(r'"accessToken":"(.*?)"', v["response"]["content"]["text"])
  65. if match:
  66. RequestConfig.access_token = match.group(1)
  67. except KeyError:
  68. pass
  69. try:
  70. if "openai-sentinel-proof-token" in v_headers:
  71. RequestConfig.headers = v_headers
  72. RequestConfig.proof_token = json.loads(base64.b64decode(
  73. v_headers["openai-sentinel-proof-token"].split("gAAAAAB", 1)[-1].encode()
  74. ).decode())
  75. if "openai-sentinel-turnstile-token" in v_headers:
  76. RequestConfig.turnstile_token = v_headers["openai-sentinel-turnstile-token"]
  77. if "authorization" in v_headers:
  78. RequestConfig.access_token = v_headers["authorization"].split(" ")[1]
  79. RequestConfig.cookies = {c['name']: c['value'] for c in v['request']['cookies']}
  80. except Exception as e:
  81. debug.log(f"Error on read headers: {e}")
  82. if RequestConfig.proof_token is None:
  83. raise NoValidHarFileError("No proof_token found in .har files")
  84. def get_headers(entry) -> dict:
  85. return {h['name'].lower(): h['value'] for h in entry['request']['headers'] if h['name'].lower() not in ['content-length', 'cookie'] and not h['name'].startswith(':')}
  86. def parseHAREntry(entry) -> arkReq:
  87. tmpArk = arkReq(
  88. arkURL=entry['request']['url'],
  89. arkBx="",
  90. arkHeader=get_headers(entry),
  91. arkBody={p['name']: unquote(p['value']) for p in entry['request']['postData']['params'] if p['name'] not in ['rnd']},
  92. arkCookies={c['name']: c['value'] for c in entry['request']['cookies']},
  93. userAgent=""
  94. )
  95. tmpArk.userAgent = tmpArk.arkHeader.get('user-agent', '')
  96. bda = tmpArk.arkBody["bda"]
  97. bw = tmpArk.arkHeader['x-ark-esync-value']
  98. tmpArk.arkBx = decrypt(bda, tmpArk.userAgent + bw)
  99. return tmpArk
  100. def genArkReq(chatArk: arkReq) -> arkReq:
  101. tmpArk: arkReq = deepcopy(chatArk)
  102. if tmpArk is None or not tmpArk.arkBody or not tmpArk.arkHeader:
  103. raise RuntimeError("The .har file is not valid")
  104. bda, bw = getBDA(tmpArk)
  105. tmpArk.arkBody['bda'] = base64.b64encode(bda.encode()).decode()
  106. tmpArk.arkBody['rnd'] = str(random.random())
  107. tmpArk.arkHeader['x-ark-esync-value'] = bw
  108. return tmpArk
  109. async def sendRequest(tmpArk: arkReq, proxy: str = None) -> str:
  110. async with StreamSession(headers=tmpArk.arkHeader, cookies=tmpArk.arkCookies, proxies={"https": proxy}) as session:
  111. async with session.post(tmpArk.arkURL, data=tmpArk.arkBody) as response:
  112. data = await response.json()
  113. arkose = data.get("token")
  114. if "sup=1|rid=" not in arkose:
  115. return RuntimeError("No valid arkose token generated")
  116. return arkose
  117. def getBDA(arkReq: arkReq):
  118. bx = arkReq.arkBx
  119. bx = re.sub(r'"key":"n","value":"\S*?"', f'"key":"n","value":"{getN()}"', bx)
  120. oldUUID_search = re.search(r'"key":"4b4b269e68","value":"(\S*?)"', bx)
  121. if oldUUID_search:
  122. oldUUID = oldUUID_search.group(1)
  123. newUUID = str(uuid.uuid4())
  124. bx = bx.replace(oldUUID, newUUID)
  125. bw = getBw(getBt())
  126. encrypted_bx = encrypt(bx, arkReq.userAgent + bw)
  127. return encrypted_bx, bw
  128. def getBt() -> int:
  129. return int(time.time())
  130. def getBw(bt: int) -> str:
  131. return str(bt - (bt % 21600))
  132. def getN() -> str:
  133. timestamp = str(int(time.time()))
  134. return base64.b64encode(timestamp.encode()).decode()
  135. async def get_request_config(proxy: str) -> RequestConfig:
  136. if RequestConfig.proof_token is None:
  137. readHAR()
  138. if RequestConfig.arkose_request is not None:
  139. RequestConfig.arkose_token = await sendRequest(genArkReq(RequestConfig.arkose_request), proxy)
  140. return RequestConfig