fingerprint.py 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. """Shared HTTP fingerprint profile helpers for ChatGPT registration and probing."""
  2. from __future__ import annotations
  3. from hashlib import sha256
  4. from typing import Any
  5. from .constants import (
  6. OPENAI_SEC_CH_UA,
  7. OPENAI_SEC_CH_UA_MOBILE,
  8. OPENAI_SEC_CH_UA_PLATFORM,
  9. OPENAI_USER_AGENT,
  10. )
  11. OPENAI_FINGERPRINT_PROFILE = "chrome120_win"
  12. _REGION_ALIASES: dict[str, tuple[str, ...]] = {
  13. "tw": ("tw", "taiwan", "台湾"),
  14. "sg": ("sg", "singapore", "新加坡"),
  15. "jp": ("jp", "japan", "日本"),
  16. "hk": ("hk", "hong kong", "香港"),
  17. "us": ("us", "usa", "united states", "美国"),
  18. }
  19. def build_browser_headers(
  20. *,
  21. access_token: str | None = None,
  22. account_id: str | None = None,
  23. accept: str = "application/json",
  24. content_type: str | None = "application/json",
  25. extra: dict[str, str] | None = None,
  26. ) -> dict[str, str]:
  27. headers = {
  28. "User-Agent": OPENAI_USER_AGENT,
  29. "sec-ch-ua": OPENAI_SEC_CH_UA,
  30. "sec-ch-ua-mobile": OPENAI_SEC_CH_UA_MOBILE,
  31. "sec-ch-ua-platform": OPENAI_SEC_CH_UA_PLATFORM,
  32. }
  33. if accept:
  34. headers["Accept"] = accept
  35. if content_type:
  36. headers["Content-Type"] = content_type
  37. if access_token:
  38. headers["Authorization"] = f"Bearer {access_token}"
  39. if account_id:
  40. headers["Chatgpt-Account-Id"] = account_id
  41. if extra:
  42. headers.update({key: value for key, value in extra.items() if value})
  43. return headers
  44. def hash_device_id(device_id: str | None) -> str:
  45. value = str(device_id or "").strip()
  46. if not value:
  47. return ""
  48. return sha256(value.encode("utf-8")).hexdigest()[:16]
  49. def infer_proxy_region(proxy_key_or_url: str | None) -> str:
  50. text = str(proxy_key_or_url or "").strip().lower()
  51. if not text:
  52. return ""
  53. for region, aliases in _REGION_ALIASES.items():
  54. if any(alias in text for alias in aliases):
  55. return region
  56. return "other"
  57. def build_registration_provenance(
  58. metadata: dict[str, Any] | None,
  59. *,
  60. proxy_url: str | None = None,
  61. proxy_key: str = "",
  62. proxy_region: str = "",
  63. cfmail_profile_name: str = "",
  64. ) -> dict[str, Any]:
  65. meta = dict(metadata or {})
  66. resolved_proxy_key = str(proxy_key or "").strip()
  67. resolved_proxy_url = str(proxy_url or "").strip()
  68. resolved_proxy_region = str(proxy_region or "").strip().lower() or infer_proxy_region(
  69. resolved_proxy_key or resolved_proxy_url
  70. )
  71. return {
  72. "registration_fingerprint_profile": OPENAI_FINGERPRINT_PROFILE,
  73. "registration_user_agent": OPENAI_USER_AGENT,
  74. "registration_sec_ch_ua": OPENAI_SEC_CH_UA,
  75. "registration_sec_ch_ua_mobile": OPENAI_SEC_CH_UA_MOBILE,
  76. "registration_sec_ch_ua_platform": OPENAI_SEC_CH_UA_PLATFORM,
  77. "registration_proxy_url": resolved_proxy_url,
  78. "registration_proxy_key": resolved_proxy_key,
  79. "registration_proxy_region": resolved_proxy_region,
  80. "registration_location": str(meta.get("location") or "").strip(),
  81. "registration_device_id_hash": hash_device_id(meta.get("device_id")),
  82. "registration_cfmail_profile_name": str(cfmail_profile_name or meta.get("cfmail_profile_name") or "").strip(),
  83. "registration_mail_provider": str(meta.get("mail_provider") or "").strip(),
  84. "registration_post_create_gate": str(meta.get("post_create_gate") or "").strip(),
  85. "registration_email_domain": str(meta.get("email_domain") or "").strip(),
  86. "registration_source": str(meta.get("source") or "").strip(),
  87. }