har_file.py 5.9 KB

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