first
This commit is contained in:
10
.gitignore
vendored
Normal file
10
.gitignore
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
# Python-generated files
|
||||
__pycache__/
|
||||
*.py[oc]
|
||||
build/
|
||||
dist/
|
||||
wheels/
|
||||
*.egg-info
|
||||
|
||||
# Virtual environments
|
||||
.venv
|
||||
1
.python-version
Normal file
1
.python-version
Normal file
@@ -0,0 +1 @@
|
||||
3.12
|
||||
1523
assets/sdk.js
Normal file
1523
assets/sdk.js
Normal file
File diff suppressed because it is too large
Load Diff
34
config.py
Normal file
34
config.py
Normal file
@@ -0,0 +1,34 @@
|
||||
# config.py
|
||||
"""全局配置"""
|
||||
|
||||
# OpenAI 端点
|
||||
AUTH_BASE_URL = "https://auth.openai.com"
|
||||
SENTINEL_BASE_URL = "https://sentinel.openai.com/sentinel"
|
||||
|
||||
# SDK 路径
|
||||
SDK_JS_PATH = "assets/sdk.js"
|
||||
|
||||
# 浏览器指纹配置
|
||||
FINGERPRINT_CONFIG = {
|
||||
'user_agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:146.0) Gecko/20100101 Firefox/146.0',
|
||||
'screen_width': 1920,
|
||||
'screen_height': 1080,
|
||||
'languages': ['en-US', 'en'],
|
||||
'hardware_concurrency': 8,
|
||||
'platform': 'Linux x86_64',
|
||||
}
|
||||
|
||||
# HTTP 配置
|
||||
HTTP_CONFIG = {
|
||||
'impersonate': 'chrome110', # curl-cffi 的浏览器模拟
|
||||
'timeout': 30,
|
||||
}
|
||||
|
||||
# PoW 配置
|
||||
POW_CONFIG = {
|
||||
'max_attempts': 500000, # SDK 默认值
|
||||
'timeout': 60, # 求解超时(秒)
|
||||
}
|
||||
|
||||
# 调试模式
|
||||
DEBUG = True
|
||||
26
download_sdk.py
Normal file
26
download_sdk.py
Normal file
@@ -0,0 +1,26 @@
|
||||
#!/usr/bin/env python3
|
||||
# download_sdk.py
|
||||
"""下载 OpenAI Sentinel SDK"""
|
||||
|
||||
import requests
|
||||
from pathlib import Path
|
||||
|
||||
SDK_URL = "https://sentinel.openai.com/sentinel/97790f37/sdk.js"
|
||||
OUTPUT_PATH = Path("assets/sdk.js")
|
||||
|
||||
def download_sdk():
|
||||
print(f"Downloading SDK from {SDK_URL}...")
|
||||
|
||||
OUTPUT_PATH.parent.mkdir(exist_ok=True)
|
||||
|
||||
resp = requests.get(SDK_URL)
|
||||
resp.raise_for_status()
|
||||
|
||||
with open(OUTPUT_PATH, 'wb') as f:
|
||||
f.write(resp.content)
|
||||
|
||||
print(f"✓ SDK saved to {OUTPUT_PATH}")
|
||||
print(f" Size: {len(resp.content) / 1024:.1f} KB")
|
||||
|
||||
if __name__ == '__main__':
|
||||
download_sdk()
|
||||
70
main.py
Normal file
70
main.py
Normal file
@@ -0,0 +1,70 @@
|
||||
#!/usr/bin/env python3
|
||||
# main.py
|
||||
"""OpenAI Sentinel Bypass - 主入口"""
|
||||
|
||||
import sys
|
||||
import argparse
|
||||
from modules import OpenAIRegistrar
|
||||
from config import DEBUG
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
description='OpenAI Registration Automation (Sentinel Bypass)'
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
'email',
|
||||
help='Email address to register'
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
'password',
|
||||
help='Password for the account'
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
'--session-id',
|
||||
help='Custom session ID (default: auto-generated UUID)',
|
||||
default=None
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
'--quiet',
|
||||
action='store_true',
|
||||
help='Suppress debug output'
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
# 设置调试模式
|
||||
if args.quiet:
|
||||
import config
|
||||
config.DEBUG = False
|
||||
|
||||
# 创建注册器
|
||||
registrar = OpenAIRegistrar(session_id=args.session_id)
|
||||
|
||||
# 执行注册
|
||||
result = registrar.register(args.email, args.password)
|
||||
|
||||
# 输出结果
|
||||
print("\n" + "="*60)
|
||||
if result['success']:
|
||||
print("✓ REGISTRATION SUCCESSFUL")
|
||||
print(f"Email: {args.email}")
|
||||
if 'data' in result:
|
||||
print(f"Response: {result['data']}")
|
||||
else:
|
||||
print("✗ REGISTRATION FAILED")
|
||||
print(f"Error: {result.get('error', 'Unknown error')}")
|
||||
if 'status_code' in result:
|
||||
print(f"Status code: {result['status_code']}")
|
||||
print("="*60)
|
||||
|
||||
# 返回退出码
|
||||
sys.exit(0 if result['success'] else 1)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
16
modules/__init__.py
Normal file
16
modules/__init__.py
Normal file
@@ -0,0 +1,16 @@
|
||||
# modules/__init__.py
|
||||
"""Sentinel Bypass 模块包"""
|
||||
|
||||
from .fingerprint import BrowserFingerprint
|
||||
from .js_executor import JSExecutor
|
||||
from .sentinel_solver import SentinelSolver
|
||||
from .http_client import HTTPClient
|
||||
from .register import OpenAIRegistrar
|
||||
|
||||
__all__ = [
|
||||
'BrowserFingerprint',
|
||||
'JSExecutor',
|
||||
'SentinelSolver',
|
||||
'HTTPClient',
|
||||
'OpenAIRegistrar',
|
||||
]
|
||||
135
modules/fingerprint.py
Normal file
135
modules/fingerprint.py
Normal file
@@ -0,0 +1,135 @@
|
||||
# modules/fingerprint.py
|
||||
"""浏览器指纹生成器"""
|
||||
|
||||
import uuid
|
||||
import random
|
||||
import time
|
||||
from datetime import datetime
|
||||
from typing import Dict, List, Any
|
||||
|
||||
from config import FINGERPRINT_CONFIG
|
||||
|
||||
|
||||
class BrowserFingerprint:
|
||||
"""生成符合 SDK 期望的浏览器指纹"""
|
||||
|
||||
def __init__(self, session_id: str = None):
|
||||
self.session_id = session_id or str(uuid.uuid4())
|
||||
self.user_agent = FINGERPRINT_CONFIG['user_agent']
|
||||
self.screen_width = FINGERPRINT_CONFIG['screen_width']
|
||||
self.screen_height = FINGERPRINT_CONFIG['screen_height']
|
||||
self.languages = FINGERPRINT_CONFIG['languages']
|
||||
self.hardware_concurrency = FINGERPRINT_CONFIG['hardware_concurrency']
|
||||
|
||||
def get_config_array(self) -> List[Any]:
|
||||
"""
|
||||
生成 SDK getConfig() 函数返回的 18 元素数组
|
||||
|
||||
对应 SDK 源码:
|
||||
[0]: screen.width + screen.height
|
||||
[1]: new Date().toString()
|
||||
[2]: performance.memory.jsHeapSizeLimit (可选)
|
||||
[3]: nonce (PoW 填充)
|
||||
[4]: navigator.userAgent
|
||||
[5]: 随机 script.src
|
||||
[6]: build ID
|
||||
[7]: navigator.language
|
||||
[8]: navigator.languages.join(',')
|
||||
[9]: 运行时间 (PoW 填充)
|
||||
[10]: 随机 navigator 属性
|
||||
[11]: 随机 document key
|
||||
[12]: 随机 window key
|
||||
[13]: performance.now()
|
||||
[14]: session UUID
|
||||
[15]: URL search params
|
||||
[16]: navigator.hardwareConcurrency
|
||||
[17]: performance.timeOrigin
|
||||
"""
|
||||
|
||||
# 模拟的 script sources
|
||||
fake_scripts = [
|
||||
"https://sentinel.openai.com/sentinel/97790f37/sdk.js",
|
||||
"https://chatgpt.com/static/js/main.abc123.js",
|
||||
"https://cdn.oaistatic.com/_next/static/chunks/main.js",
|
||||
]
|
||||
|
||||
# 模拟的 navigator 属性名
|
||||
navigator_props = [
|
||||
'hardwareConcurrency', 'language', 'languages',
|
||||
'platform', 'userAgent', 'vendor'
|
||||
]
|
||||
|
||||
# 模拟的 document keys
|
||||
document_keys = ['body', 'head', 'documentElement', 'scripts']
|
||||
|
||||
# 模拟的 window keys
|
||||
window_keys = ['performance', 'navigator', 'document', 'location']
|
||||
|
||||
current_time = time.time() * 1000
|
||||
|
||||
return [
|
||||
self.screen_width + self.screen_height, # [0]
|
||||
str(datetime.now()), # [1]
|
||||
None, # [2] memory
|
||||
None, # [3] nonce (placeholder)
|
||||
self.user_agent, # [4]
|
||||
random.choice(fake_scripts), # [5]
|
||||
"97790f37", # [6] build ID
|
||||
self.languages[0], # [7]
|
||||
",".join(self.languages), # [8]
|
||||
None, # [9] runtime (placeholder)
|
||||
f"{random.choice(navigator_props)}−{random.randint(1, 16)}", # [10]
|
||||
random.choice(document_keys), # [11]
|
||||
random.choice(window_keys), # [12]
|
||||
current_time, # [13]
|
||||
self.session_id, # [14]
|
||||
"", # [15] URL params
|
||||
self.hardware_concurrency, # [16]
|
||||
current_time - random.uniform(100, 1000), # [17] timeOrigin
|
||||
]
|
||||
|
||||
def get_cookies(self) -> Dict[str, str]:
|
||||
"""生成初始 cookies"""
|
||||
return {
|
||||
'oai-did': self.session_id,
|
||||
}
|
||||
|
||||
def get_headers(self, with_sentinel: str = None) -> Dict[str, str]:
|
||||
"""生成 HTTP headers"""
|
||||
|
||||
# 基础 headers
|
||||
headers = {
|
||||
'User-Agent': self.user_agent,
|
||||
'Accept': 'application/json',
|
||||
'Accept-Language': f"{self.languages[0]},{self.languages[1]};q=0.5",
|
||||
'Accept-Encoding': 'gzip, deflate, br, zstd',
|
||||
'Referer': 'https://auth.openai.com/create-account/password',
|
||||
'Content-Type': 'application/json',
|
||||
'Origin': 'https://auth.openai.com',
|
||||
'Connection': 'keep-alive',
|
||||
'Sec-Fetch-Dest': 'empty',
|
||||
'Sec-Fetch-Mode': 'cors',
|
||||
'Sec-Fetch-Site': 'same-origin',
|
||||
'Priority': 'u=4',
|
||||
'Pragma': 'no-cache',
|
||||
'Cache-Control': 'no-cache',
|
||||
}
|
||||
|
||||
# Sentinel token
|
||||
if with_sentinel:
|
||||
headers['openai-sentinel-token'] = with_sentinel
|
||||
|
||||
# Datadog RUM tracing (OpenAI 使用)
|
||||
trace_id = random.randint(10**18, 10**19 - 1)
|
||||
parent_id = random.randint(10**18, 10**19 - 1)
|
||||
|
||||
headers.update({
|
||||
'traceparent': f'00-0000000000000000{trace_id:016x}-{parent_id:016x}-01',
|
||||
'tracestate': 'dd=s:1;o:rum',
|
||||
'x-datadog-origin': 'rum',
|
||||
'x-datadog-parent-id': str(parent_id),
|
||||
'x-datadog-sampling-priority': '1',
|
||||
'x-datadog-trace-id': str(trace_id),
|
||||
})
|
||||
|
||||
return headers
|
||||
181
modules/http_client.py
Normal file
181
modules/http_client.py
Normal file
@@ -0,0 +1,181 @@
|
||||
# modules/http_client.py
|
||||
"""HTTP 客户端(支持 CSRF token)"""
|
||||
|
||||
from typing import Dict, Optional
|
||||
import requests
|
||||
from requests.adapters import HTTPAdapter
|
||||
from urllib3.util.ssl_ import create_urllib3_context
|
||||
from urllib.parse import unquote
|
||||
|
||||
from .fingerprint import BrowserFingerprint
|
||||
from config import HTTP_CONFIG, DEBUG
|
||||
|
||||
|
||||
class TLSAdapter(HTTPAdapter):
|
||||
"""自定义 TLS 适配器"""
|
||||
def init_poolmanager(self, *args, **kwargs):
|
||||
ctx = create_urllib3_context()
|
||||
ctx.set_ciphers(
|
||||
'TLS_AES_128_GCM_SHA256:'
|
||||
'TLS_AES_256_GCM_SHA384:'
|
||||
'TLS_CHACHA20_POLY1305_SHA256:'
|
||||
'ECDHE-ECDSA-AES128-GCM-SHA256:'
|
||||
'ECDHE-RSA-AES128-GCM-SHA256'
|
||||
)
|
||||
kwargs['ssl_context'] = ctx
|
||||
return super().init_poolmanager(*args, **kwargs)
|
||||
|
||||
|
||||
class HTTPClient:
|
||||
"""HTTP 客户端(自动处理 CSRF)"""
|
||||
|
||||
def __init__(self, fingerprint: BrowserFingerprint):
|
||||
self.fingerprint = fingerprint
|
||||
self.session = requests.Session()
|
||||
|
||||
adapter = TLSAdapter()
|
||||
self.session.mount('https://', adapter)
|
||||
|
||||
self.cookies = fingerprint.get_cookies()
|
||||
self.csrf_token = None
|
||||
|
||||
def extract_csrf_from_cookies(self) -> Optional[str]:
|
||||
"""从 cookies 中提取 CSRF token"""
|
||||
csrf_cookie = self.cookies.get('__Host-next-auth.csrf-token')
|
||||
|
||||
if not csrf_cookie:
|
||||
return None
|
||||
|
||||
try:
|
||||
decoded = unquote(csrf_cookie)
|
||||
token = decoded.split('|')[0]
|
||||
|
||||
if DEBUG:
|
||||
print(f"[HTTP] Extracted CSRF from cookie: {token[:20]}...")
|
||||
|
||||
return token
|
||||
except Exception as e:
|
||||
if DEBUG:
|
||||
print(f"[HTTP] Failed to extract CSRF: {e}")
|
||||
return None
|
||||
|
||||
def get(self, url: str, **kwargs) -> requests.Response:
|
||||
"""GET 请求"""
|
||||
kwargs.setdefault('headers', self.fingerprint.get_headers())
|
||||
kwargs.setdefault('cookies', self.cookies)
|
||||
kwargs.setdefault('timeout', HTTP_CONFIG['timeout'])
|
||||
|
||||
if DEBUG:
|
||||
print(f"[HTTP] GET {url}")
|
||||
|
||||
resp = self.session.get(url, **kwargs)
|
||||
|
||||
# 更新 cookies
|
||||
self.cookies.update(resp.cookies.get_dict())
|
||||
|
||||
# 尝试提取 CSRF
|
||||
csrf = self.extract_csrf_from_cookies()
|
||||
if csrf:
|
||||
self.csrf_token = csrf
|
||||
|
||||
if DEBUG:
|
||||
print(f"[HTTP] Response: {resp.status_code}")
|
||||
print(f"Cookies: {list(self.cookies.keys())}")
|
||||
|
||||
return resp
|
||||
|
||||
def get_csrf_token(self) -> Optional[str]:
|
||||
"""
|
||||
获取 CSRF token
|
||||
|
||||
尝试多种方法:
|
||||
1. 从现有 cookie 提取
|
||||
2. 访问 /api/auth/csrf
|
||||
3. 如果都失败,返回 None(某些流程可能不需要)
|
||||
"""
|
||||
# 1. 从 cookie 提取
|
||||
csrf = self.extract_csrf_from_cookies()
|
||||
if csrf:
|
||||
self.csrf_token = csrf
|
||||
return csrf
|
||||
|
||||
# 2. 访问 /api/auth/csrf
|
||||
if DEBUG:
|
||||
print("[HTTP] Requesting CSRF token from /api/auth/csrf...")
|
||||
|
||||
try:
|
||||
url = "https://auth.openai.com/api/auth/csrf"
|
||||
|
||||
resp = self.session.get(
|
||||
url,
|
||||
headers=self.fingerprint.get_headers(),
|
||||
cookies=self.cookies,
|
||||
timeout=HTTP_CONFIG['timeout']
|
||||
)
|
||||
|
||||
# 更新 cookies
|
||||
self.cookies.update(resp.cookies.get_dict())
|
||||
|
||||
# 尝试从 cookie 提取
|
||||
csrf = self.extract_csrf_from_cookies()
|
||||
if csrf:
|
||||
self.csrf_token = csrf
|
||||
return csrf
|
||||
|
||||
# 尝试从 JSON 提取
|
||||
if resp.status_code == 200:
|
||||
try:
|
||||
data = resp.json()
|
||||
csrf = data.get('csrfToken')
|
||||
if csrf:
|
||||
self.csrf_token = csrf
|
||||
return csrf
|
||||
except:
|
||||
pass
|
||||
|
||||
except Exception as e:
|
||||
if DEBUG:
|
||||
print(f"[HTTP] Failed to get CSRF token: {e}")
|
||||
|
||||
# 3. 失败,返回 None
|
||||
if DEBUG:
|
||||
print("[HTTP] ⚠ CSRF token not available (may not be required)")
|
||||
|
||||
return None
|
||||
|
||||
def post(self, url: str, json_data: Optional[Dict] = None,
|
||||
sentinel_token: Optional[str] = None, **kwargs) -> requests.Response:
|
||||
"""POST 请求"""
|
||||
|
||||
headers = self.fingerprint.get_headers(with_sentinel=sentinel_token)
|
||||
|
||||
# 添加 CSRF token(如果有)
|
||||
if self.csrf_token:
|
||||
headers['openai-sentinel-csrf-token'] = self.csrf_token
|
||||
|
||||
# 添加必需 headers
|
||||
headers['Referer'] = 'https://auth.openai.com/'
|
||||
headers['Origin'] = 'https://auth.openai.com'
|
||||
|
||||
kwargs.setdefault('headers', headers)
|
||||
kwargs.setdefault('cookies', self.cookies)
|
||||
kwargs.setdefault('timeout', HTTP_CONFIG['timeout'])
|
||||
|
||||
if json_data:
|
||||
kwargs['json'] = json_data
|
||||
|
||||
if DEBUG:
|
||||
print(f"[HTTP] POST {url}")
|
||||
if self.csrf_token:
|
||||
print(f"[HTTP] With CSRF token: {self.csrf_token[:20]}...")
|
||||
if sentinel_token:
|
||||
print(f"[HTTP] With Sentinel token: {sentinel_token[:50]}...")
|
||||
|
||||
resp = self.session.post(url, **kwargs)
|
||||
|
||||
self.cookies.update(resp.cookies.get_dict())
|
||||
|
||||
if DEBUG:
|
||||
print(f"[HTTP] Response: {resp.status_code}")
|
||||
|
||||
return resp
|
||||
245
modules/js_executor.py
Normal file
245
modules/js_executor.py
Normal file
@@ -0,0 +1,245 @@
|
||||
"""JavaScript 执行引擎封装
|
||||
|
||||
说明:
|
||||
- OpenAI 的 `assets/sdk.js` 是浏览器脚本,包含多段 anti-debug 代码与 DOM 初始化逻辑。
|
||||
- 直接用 PyExecJS/ExecJS 在 Node 环境执行时,常见表现是「compile 成功但 call 卡死」。
|
||||
- 这里改为通过 `node -` 运行一段自包含脚本:先做轻量净化 + browser shim,再执行目标函数并强制输出结果。
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import re
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
from typing import Any, Dict, Optional
|
||||
|
||||
from config import DEBUG, SDK_JS_PATH
|
||||
|
||||
|
||||
class JSExecutor:
|
||||
"""通过 Node.js 执行 Sentinel SDK 内部逻辑(支持 async Turnstile VM)"""
|
||||
|
||||
def __init__(self):
|
||||
self._sdk_code: str = ""
|
||||
self._load_sdk()
|
||||
|
||||
def _load_sdk(self) -> None:
|
||||
sdk_path = Path(SDK_JS_PATH)
|
||||
if not sdk_path.exists():
|
||||
raise FileNotFoundError(f"SDK not found at {SDK_JS_PATH}")
|
||||
|
||||
sdk_code = sdk_path.read_text(encoding="utf-8")
|
||||
sdk_code = self._sanitize_sdk(sdk_code)
|
||||
sdk_code = self._inject_internal_exports(sdk_code)
|
||||
|
||||
self._sdk_code = sdk_code
|
||||
|
||||
if DEBUG:
|
||||
print("[JSExecutor] SDK loaded successfully (sanitized)")
|
||||
|
||||
def _sanitize_sdk(self, sdk_code: str) -> str:
|
||||
"""移除会在 Node 环境中导致卡死/超慢的 anti-debug 片段。"""
|
||||
# 1) 删除少量已知的顶层 anti-debug 直接调用(独占一行)
|
||||
sdk_code = re.sub(r"(?m)^\s*[rugkU]\(\);\s*$", "", sdk_code)
|
||||
sdk_code = re.sub(r"(?m)^\s*o\(\);\s*$", "", sdk_code)
|
||||
|
||||
# 2) 删除 `Pt(),` 这种逗号表达式里的 anti-debug 调用(避免语法破坏)
|
||||
sdk_code = re.sub(r"\bPt\(\),\s*", "", sdk_code)
|
||||
sdk_code = re.sub(r"\bPt\(\);\s*", "", sdk_code)
|
||||
|
||||
# 3) 删除 class 字段初始化里的 anti-debug 调用:`return n(), "" + Math.random();`
|
||||
sdk_code = re.sub(
|
||||
r'return\s+n\(\),\s*""\s*\+\s*Math\.random\(\)\s*;',
|
||||
'return "" + Math.random();',
|
||||
sdk_code,
|
||||
)
|
||||
|
||||
# 4) 删除类似 `if ((e(), cond))` 的逗号 anti-debug 调用(保留 cond)
|
||||
# 仅处理极短标识符,避免误伤正常逻辑;保留 Turnstile VM 的 `vt()`。
|
||||
def _strip_comma_call(match: re.Match[str]) -> str:
|
||||
fn = match.group(1)
|
||||
if fn == "vt":
|
||||
return match.group(0)
|
||||
return "("
|
||||
|
||||
sdk_code = re.sub(
|
||||
r"\(\s*([A-Za-z_$][A-Za-z0-9_$]{0,2})\(\)\s*,",
|
||||
_strip_comma_call,
|
||||
sdk_code,
|
||||
)
|
||||
return sdk_code
|
||||
|
||||
def _inject_internal_exports(self, sdk_code: str) -> str:
|
||||
"""把 SDK 内部对象导出到 `SentinelSDK` 上,便于在外部调用。"""
|
||||
# SDK 末尾一般是:
|
||||
# (t.init = un),
|
||||
# (t.token = an),
|
||||
# t
|
||||
# );
|
||||
pattern = re.compile(
|
||||
r"\(\s*t\.init\s*=\s*un\s*\)\s*,\s*\(\s*t\.token\s*=\s*an\s*\)\s*,\s*t\s*\)",
|
||||
re.MULTILINE,
|
||||
)
|
||||
|
||||
replacement = (
|
||||
"(t.init = un),"
|
||||
"(t.token = an),"
|
||||
"(t.__O = O),"
|
||||
"(t.__P = P),"
|
||||
"(t.__bt = bt),"
|
||||
"(t.__kt = kt),"
|
||||
"(t.__Kt = Kt),"
|
||||
"t)"
|
||||
)
|
||||
|
||||
new_code, n = pattern.subn(replacement, sdk_code, count=1)
|
||||
if n != 1:
|
||||
raise RuntimeError("Failed to patch SDK exports; SDK format may have changed.")
|
||||
return new_code
|
||||
|
||||
def _node_script(self, payload: Dict[str, Any], entry: str) -> str:
|
||||
payload_json = json.dumps(payload, ensure_ascii=False)
|
||||
|
||||
shim = r"""
|
||||
// --- minimal browser shims for Node ---
|
||||
if (typeof globalThis.window !== "object") globalThis.window = globalThis;
|
||||
if (!window.top) window.top = window;
|
||||
if (!window.location) window.location = { href: "https://auth.openai.com/create-account/password", search: "", pathname: "/create-account/password", origin: "https://auth.openai.com" };
|
||||
if (!window.addEventListener) window.addEventListener = function(){};
|
||||
if (!window.removeEventListener) window.removeEventListener = function(){};
|
||||
if (!window.postMessage) window.postMessage = function(){};
|
||||
if (!window.__sentinel_token_pending) window.__sentinel_token_pending = [];
|
||||
if (!window.__sentinel_init_pending) window.__sentinel_init_pending = [];
|
||||
|
||||
if (typeof globalThis.document !== "object") globalThis.document = {};
|
||||
if (!document.scripts) document.scripts = [];
|
||||
if (!document.cookie) document.cookie = "";
|
||||
if (!document.documentElement) document.documentElement = { getAttribute: () => null };
|
||||
if (!document.currentScript) document.currentScript = null;
|
||||
if (!document.body) document.body = { appendChild: function(){}, getAttribute: () => null };
|
||||
if (!document.createElement) document.createElement = function(tag){
|
||||
return {
|
||||
tagName: String(tag||"").toUpperCase(),
|
||||
style: {},
|
||||
setAttribute: function(){},
|
||||
getAttribute: function(){ return null; },
|
||||
addEventListener: function(){},
|
||||
removeEventListener: function(){},
|
||||
src: "",
|
||||
contentWindow: { postMessage: function(){}, addEventListener: function(){}, removeEventListener: function(){} },
|
||||
};
|
||||
};
|
||||
|
||||
if (typeof globalThis.navigator !== "object") globalThis.navigator = { userAgent: "ua", language: "en-US", languages: ["en-US","en"], hardwareConcurrency: 8 };
|
||||
if (typeof globalThis.screen !== "object") globalThis.screen = { width: 1920, height: 1080 };
|
||||
if (typeof globalThis.btoa !== "function") globalThis.btoa = (str) => Buffer.from(str, "binary").toString("base64");
|
||||
if (typeof globalThis.atob !== "function") globalThis.atob = (b64) => Buffer.from(b64, "base64").toString("binary");
|
||||
window.btoa = globalThis.btoa;
|
||||
window.atob = globalThis.atob;
|
||||
"""
|
||||
|
||||
wrapper = f"""
|
||||
const __payload = {payload_json};
|
||||
|
||||
function __makeSolver(configArray) {{
|
||||
const solver = new SentinelSDK.__O();
|
||||
solver.sid = configArray?.[14];
|
||||
// 强制使用 Python 传入的 configArray,避免依赖真实浏览器对象
|
||||
solver.getConfig = () => configArray;
|
||||
return solver;
|
||||
}}
|
||||
|
||||
async function __entry() {{
|
||||
{entry}
|
||||
}}
|
||||
|
||||
(async () => {{
|
||||
try {{
|
||||
const result = await __entry();
|
||||
process.stdout.write(JSON.stringify({{ ok: true, result }}), () => process.exit(0));
|
||||
}} catch (err) {{
|
||||
const msg = (err && (err.stack || err.message)) ? (err.stack || err.message) : String(err);
|
||||
process.stdout.write(JSON.stringify({{ ok: false, error: msg }}), () => process.exit(1));
|
||||
}}
|
||||
}})();
|
||||
"""
|
||||
return "\n".join([shim, self._sdk_code, wrapper])
|
||||
|
||||
def _run_node(self, payload: Dict[str, Any], entry: str, timeout_s: int = 30) -> Any:
|
||||
script = self._node_script(payload, entry)
|
||||
|
||||
if DEBUG:
|
||||
print("[JSExecutor] Running Node worker...")
|
||||
|
||||
try:
|
||||
proc = subprocess.run(
|
||||
["node", "-"],
|
||||
input=script,
|
||||
text=True,
|
||||
capture_output=True,
|
||||
timeout=timeout_s,
|
||||
)
|
||||
except FileNotFoundError as e:
|
||||
raise RuntimeError("Node.js not found on PATH (required for Sentinel SDK execution).") from e
|
||||
except subprocess.TimeoutExpired as e:
|
||||
raise TimeoutError(f"Node worker timed out after {timeout_s}s") from e
|
||||
|
||||
stdout = (proc.stdout or "").strip()
|
||||
if not stdout:
|
||||
raise RuntimeError(f"Node worker produced no output (stderr={proc.stderr!r})")
|
||||
|
||||
try:
|
||||
obj = json.loads(stdout)
|
||||
except json.JSONDecodeError as e:
|
||||
raise RuntimeError(f"Node worker returned non-JSON output: {stdout[:200]!r}") from e
|
||||
|
||||
if not obj.get("ok"):
|
||||
raise RuntimeError(obj.get("error", "Unknown JS error"))
|
||||
|
||||
return obj.get("result")
|
||||
|
||||
def solve_pow(self, seed: str, difficulty: str, config_array: list) -> str:
|
||||
if DEBUG:
|
||||
print(f"[JSExecutor] Solving PoW: seed={seed[:10]}..., difficulty={difficulty}")
|
||||
|
||||
result = self._run_node(
|
||||
{"seed": seed, "difficulty": difficulty, "configArray": config_array},
|
||||
entry="return __makeSolver(__payload.configArray)._generateAnswerSync(__payload.seed, __payload.difficulty);",
|
||||
timeout_s=60,
|
||||
)
|
||||
|
||||
if DEBUG and isinstance(result, str):
|
||||
print(f"[JSExecutor] PoW solved: {result[:50]}...")
|
||||
|
||||
return result
|
||||
|
||||
def generate_requirements(self, seed: str, config_array: list) -> str:
|
||||
result = self._run_node(
|
||||
{"seed": seed, "configArray": config_array},
|
||||
entry=(
|
||||
"const solver = __makeSolver(__payload.configArray);\n"
|
||||
"solver.requirementsSeed = __payload.seed;\n"
|
||||
"return solver._generateRequirementsTokenAnswerBlocking();"
|
||||
),
|
||||
timeout_s=30,
|
||||
)
|
||||
return result
|
||||
|
||||
def execute_turnstile(self, dx_bytecode: str, xor_key: str) -> str:
|
||||
if DEBUG:
|
||||
print("[JSExecutor] Executing Turnstile VM...")
|
||||
|
||||
result = self._run_node(
|
||||
{"dx": dx_bytecode, "xorKey": xor_key},
|
||||
entry=(
|
||||
"SentinelSDK.__kt(__payload.xorKey);\n"
|
||||
"return await SentinelSDK.__bt(__payload.dx);"
|
||||
),
|
||||
timeout_s=30,
|
||||
)
|
||||
|
||||
if DEBUG and isinstance(result, str):
|
||||
print(f"[JSExecutor] Turnstile result: {result[:50]}...")
|
||||
|
||||
return result
|
||||
242
modules/register.py
Normal file
242
modules/register.py
Normal file
@@ -0,0 +1,242 @@
|
||||
# modules/registrar.py (更新版)
|
||||
"""OpenAI 注册流程控制器"""
|
||||
|
||||
import json
|
||||
from typing import Dict, Optional
|
||||
import secrets
|
||||
|
||||
from .fingerprint import BrowserFingerprint
|
||||
from .sentinel_solver import SentinelSolver
|
||||
from .http_client import HTTPClient
|
||||
from config import AUTH_BASE_URL, DEBUG
|
||||
|
||||
|
||||
class OpenAIRegistrar:
|
||||
"""完整的 OpenAI 注册流程"""
|
||||
|
||||
def __init__(self, session_id: Optional[str] = None):
|
||||
self.fingerprint = BrowserFingerprint(session_id)
|
||||
self.solver = SentinelSolver(self.fingerprint)
|
||||
self.http_client = HTTPClient(self.fingerprint)
|
||||
|
||||
def _step1_get_cookies_and_csrf(self):
|
||||
"""访问注册页,获取必需的 session cookies"""
|
||||
if DEBUG:
|
||||
print("\n=== STEP 1: Getting session cookies ===")
|
||||
|
||||
# 访问注册页(会设置 login_session 等 cookies)
|
||||
url = f"{AUTH_BASE_URL}/create-account/password"
|
||||
|
||||
headers = self.http_client.fingerprint.get_headers()
|
||||
headers['Accept'] = 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8'
|
||||
|
||||
resp = self.http_client.get(url, headers=headers)
|
||||
|
||||
if DEBUG:
|
||||
print(f"Cookies received: {list(self.http_client.cookies.keys())}")
|
||||
|
||||
# 检查关键 cookies
|
||||
required_cookies = ['oai-did', 'login_session', 'oai-client-auth-session']
|
||||
missing = [c for c in required_cookies if c not in self.http_client.cookies]
|
||||
|
||||
if missing:
|
||||
print(f"⚠ Warning: Missing cookies: {missing}")
|
||||
else:
|
||||
print(f"✓ All required cookies present")
|
||||
|
||||
def _step2_init_sentinel(self):
|
||||
"""初始化 Sentinel(生成 token)"""
|
||||
if DEBUG:
|
||||
print("\n=== STEP 2: Initializing Sentinel ===")
|
||||
|
||||
try:
|
||||
token_data = self.solver.generate_requirements_token()
|
||||
self.sentinel_token = json.dumps(token_data)
|
||||
|
||||
if DEBUG:
|
||||
token_str = str(self.sentinel_token)
|
||||
print(f"✓ Sentinel token: {token_str[:80]}...")
|
||||
|
||||
except Exception as e:
|
||||
if DEBUG:
|
||||
print(f"✗ Sentinel initialization failed: {e}")
|
||||
raise
|
||||
|
||||
def _step3_attempt_register(self, email: str, password: str) -> Dict:
|
||||
"""尝试注册(会触发 enforcement)"""
|
||||
if DEBUG:
|
||||
print("\n=== STEP 3: Attempting registration ===")
|
||||
|
||||
url = f"{AUTH_BASE_URL}/api/accounts/user/register"
|
||||
|
||||
# 正确的 payload 格式(根据真实抓包)
|
||||
payload = {
|
||||
'username': email,
|
||||
'password': password
|
||||
}
|
||||
|
||||
# 添加额外的 headers
|
||||
headers = self.http_client.fingerprint.get_headers(with_sentinel=self.sentinel_token)
|
||||
headers['Accept'] = 'application/json'
|
||||
headers['Referer'] = f'{AUTH_BASE_URL}/create-account/password'
|
||||
headers['Origin'] = AUTH_BASE_URL
|
||||
|
||||
# 添加 Datadog tracing headers(模拟真实浏览器)
|
||||
headers.update({
|
||||
'traceparent': f'00-0000000000000000{secrets.token_hex(8)}-{secrets.token_hex(8)}-01',
|
||||
'tracestate': 'dd=s:1;o:rum',
|
||||
'x-datadog-origin': 'rum',
|
||||
'x-datadog-parent-id': str(secrets.randbits(63)),
|
||||
'x-datadog-sampling-priority': '1',
|
||||
'x-datadog-trace-id': str(secrets.randbits(63))
|
||||
})
|
||||
|
||||
resp = self.http_client.session.post(
|
||||
url,
|
||||
json=payload,
|
||||
headers=headers,
|
||||
cookies=self.http_client.cookies,
|
||||
)
|
||||
|
||||
if DEBUG:
|
||||
print(f"Response status: {resp.status_code}")
|
||||
|
||||
# 更新 cookies
|
||||
self.http_client.cookies.update(resp.cookies.get_dict())
|
||||
|
||||
# 403: Enforcement 挑战(预期)
|
||||
if resp.status_code == 403:
|
||||
try:
|
||||
challenge = resp.json()
|
||||
|
||||
if DEBUG:
|
||||
print(f"✓ Got enforcement challenge!")
|
||||
print(f" Type: {challenge.get('type', 'unknown')}")
|
||||
if 'proofofwork' in challenge:
|
||||
pow_data = challenge['proofofwork']
|
||||
print(f" PoW seed: {pow_data.get('seed', 'N/A')}")
|
||||
print(f" Difficulty: {pow_data.get('difficulty', 'N/A')}")
|
||||
|
||||
return challenge
|
||||
|
||||
except Exception as e:
|
||||
if DEBUG:
|
||||
print(f"✗ Failed to parse challenge: {e}")
|
||||
print(resp.text[:500])
|
||||
raise
|
||||
|
||||
# 200: 成功
|
||||
elif resp.status_code == 200:
|
||||
if DEBUG:
|
||||
print("✓ Registration succeeded!")
|
||||
return {'success': True, 'data': resp.json()}
|
||||
|
||||
# 409: Invalid session
|
||||
elif resp.status_code == 409:
|
||||
error = resp.json()
|
||||
if DEBUG:
|
||||
print(f"✗ 409: {error}")
|
||||
raise Exception(f"Invalid session: {error}")
|
||||
|
||||
# 400: 参数错误
|
||||
elif resp.status_code == 400:
|
||||
error = resp.json()
|
||||
if DEBUG:
|
||||
print(f"✗ 400: {error}")
|
||||
raise Exception(f"Bad request: {error}")
|
||||
|
||||
# 其他错误
|
||||
else:
|
||||
if DEBUG:
|
||||
print(f"✗ Unexpected status: {resp.status_code}")
|
||||
print(resp.text[:500])
|
||||
raise Exception(f"Unexpected status: {resp.status_code}\n{resp.text}")
|
||||
|
||||
|
||||
|
||||
|
||||
def _step4_solve_challenge(self, challenge: Dict) -> str:
|
||||
"""解决 enforcement 挑战"""
|
||||
if DEBUG:
|
||||
print("\n=== STEP 4: Solving enforcement challenge ===")
|
||||
|
||||
sentinel_token = self.solver.solve_enforcement(challenge)
|
||||
|
||||
return sentinel_token
|
||||
|
||||
def _step5_register_with_token(self, email: str, password: str,
|
||||
sentinel_token: str) -> Dict:
|
||||
"""带 Sentinel token 重新注册"""
|
||||
if DEBUG:
|
||||
print("\n=== STEP 5: Registering with Sentinel token ===")
|
||||
|
||||
url = f"{AUTH_BASE_URL}/api/accounts/user/register"
|
||||
|
||||
payload = {
|
||||
'username': email,
|
||||
'password': password,
|
||||
'client_id': 'sentinel'
|
||||
}
|
||||
|
||||
resp = self.http_client.post(
|
||||
url,
|
||||
json_data=payload,
|
||||
sentinel_token=sentinel_token
|
||||
)
|
||||
|
||||
if resp.status_code == 200:
|
||||
if DEBUG:
|
||||
print("✓ Registration successful!")
|
||||
return {'success': True, 'data': resp.json()}
|
||||
|
||||
else:
|
||||
if DEBUG:
|
||||
print(f"✗ Registration failed: {resp.status_code}")
|
||||
print(resp.text)
|
||||
|
||||
return {
|
||||
'success': False,
|
||||
'status_code': resp.status_code,
|
||||
'error': resp.text
|
||||
}
|
||||
|
||||
def register(self, email: str, password: str) -> Dict:
|
||||
"""完整注册流程"""
|
||||
if DEBUG:
|
||||
print(f"\n{'='*60}")
|
||||
print(f"Registering: {email}")
|
||||
print(f"Session ID: {self.fingerprint.session_id}")
|
||||
print(f"{'='*60}")
|
||||
|
||||
try:
|
||||
# Step 1: 获取 cookies 和 CSRF token
|
||||
self._step1_get_cookies_and_csrf()
|
||||
|
||||
# Step 2: 初始化 Sentinel(跳过)
|
||||
self._step2_init_sentinel()
|
||||
|
||||
# Step 3: 尝试注册(获取挑战)
|
||||
challenge = self._step3_attempt_register(email, password)
|
||||
|
||||
# 如果直接成功了
|
||||
if challenge.get('success'):
|
||||
return challenge
|
||||
|
||||
# Step 4: 解决挑战
|
||||
sentinel_token = self._step4_solve_challenge(challenge)
|
||||
|
||||
# Step 5: 带 token 重新注册
|
||||
result = self._step5_register_with_token(email, password, sentinel_token)
|
||||
|
||||
return result
|
||||
|
||||
except Exception as e:
|
||||
if DEBUG:
|
||||
import traceback
|
||||
print(f"\n✗ Registration failed with exception:")
|
||||
traceback.print_exc()
|
||||
|
||||
return {
|
||||
'success': False,
|
||||
'error': str(e)
|
||||
}
|
||||
113
modules/sentinel_solver.py
Normal file
113
modules/sentinel_solver.py
Normal file
@@ -0,0 +1,113 @@
|
||||
# modules/sentinel_solver.py
|
||||
"""Sentinel 挑战求解器"""
|
||||
|
||||
import json
|
||||
import uuid
|
||||
from typing import Dict, Optional
|
||||
|
||||
from .js_executor import JSExecutor
|
||||
from .fingerprint import BrowserFingerprint
|
||||
from config import DEBUG
|
||||
|
||||
|
||||
class SentinelSolver:
|
||||
"""协调指纹生成和 JS 执行,生成完整的 Sentinel tokens"""
|
||||
|
||||
def __init__(self, fingerprint: BrowserFingerprint):
|
||||
self.fingerprint = fingerprint
|
||||
self.js_executor = JSExecutor()
|
||||
|
||||
def generate_requirements_token(self) -> Dict[str, str]:
|
||||
"""
|
||||
生成 requirements token(初始化时需要)
|
||||
|
||||
Returns:
|
||||
{'p': 'gAAAAAC...', 'id': 'uuid'}
|
||||
"""
|
||||
if DEBUG:
|
||||
print("[Solver] Generating requirements token...")
|
||||
|
||||
# 生成随机 seed
|
||||
req_seed = str(uuid.uuid4())
|
||||
|
||||
# 获取指纹配置
|
||||
config_array = self.fingerprint.get_config_array()
|
||||
|
||||
# 调用 JS 求解
|
||||
answer = self.js_executor.generate_requirements(req_seed, config_array)
|
||||
|
||||
token = {
|
||||
'p': f'gAAAAAC{answer}',
|
||||
'id': self.fingerprint.session_id,
|
||||
}
|
||||
|
||||
if DEBUG:
|
||||
print(f"[Solver] Requirements token: {token['p'][:30]}...")
|
||||
|
||||
return token
|
||||
|
||||
def solve_enforcement(self, enforcement_config: Dict) -> str:
|
||||
"""
|
||||
解决完整的 enforcement 挑战(PoW + Turnstile)
|
||||
|
||||
Args:
|
||||
enforcement_config: 服务器返回的挑战配置
|
||||
{
|
||||
'proofofwork': {
|
||||
'seed': '...',
|
||||
'difficulty': '0003a',
|
||||
'token': '...', # cached token
|
||||
'turnstile': {
|
||||
'dx': '...' # VM bytecode
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Returns:
|
||||
完整的 Sentinel token (JSON string)
|
||||
"""
|
||||
if DEBUG:
|
||||
print("[Solver] Solving enforcement challenge...")
|
||||
|
||||
pow_data = enforcement_config.get('proofofwork', {})
|
||||
|
||||
# 1. 解决 PoW
|
||||
seed = pow_data['seed']
|
||||
difficulty = pow_data['difficulty']
|
||||
|
||||
config_array = self.fingerprint.get_config_array()
|
||||
pow_answer = self.js_executor.solve_pow(seed, difficulty, config_array)
|
||||
|
||||
# 2. 执行 Turnstile(如果有)
|
||||
turnstile_result = None
|
||||
turnstile_data = pow_data.get('turnstile')
|
||||
|
||||
if turnstile_data and turnstile_data.get('dx'):
|
||||
dx_bytecode = turnstile_data['dx']
|
||||
xor_key = self.fingerprint.session_id # 通常用 session ID 作为密钥
|
||||
|
||||
turnstile_result = self.js_executor.execute_turnstile(dx_bytecode, xor_key)
|
||||
|
||||
# 3. 构建最终 token
|
||||
sentinel_token = {
|
||||
# enforcement token 前缀为 gAAAAAB(requirements 为 gAAAAAC)
|
||||
'p': f'gAAAAAB{pow_answer}',
|
||||
'id': self.fingerprint.session_id,
|
||||
'flow': 'username_password_create',
|
||||
}
|
||||
|
||||
# 添加可选字段
|
||||
if turnstile_result:
|
||||
sentinel_token['t'] = turnstile_result
|
||||
|
||||
if pow_data.get('token'):
|
||||
sentinel_token['c'] = pow_data['token']
|
||||
|
||||
token_json = json.dumps(sentinel_token)
|
||||
|
||||
if DEBUG:
|
||||
print(f"[Solver] Sentinel token generated: {token_json[:80]}...")
|
||||
|
||||
return token_json
|
||||
|
||||
|
||||
11
pyproject.toml
Normal file
11
pyproject.toml
Normal file
@@ -0,0 +1,11 @@
|
||||
[project]
|
||||
name = "autoreg"
|
||||
version = "0.1.0"
|
||||
description = "Add your description here"
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.12"
|
||||
dependencies = [
|
||||
"curl-cffi>=0.14.0",
|
||||
"pyexecjs>=1.5.1",
|
||||
"requests>=2.32.5",
|
||||
]
|
||||
226
uv.lock
generated
Normal file
226
uv.lock
generated
Normal file
@@ -0,0 +1,226 @@
|
||||
version = 1
|
||||
revision = 3
|
||||
requires-python = ">=3.12"
|
||||
|
||||
[[package]]
|
||||
name = "autoreg"
|
||||
version = "0.1.0"
|
||||
source = { virtual = "." }
|
||||
dependencies = [
|
||||
{ name = "curl-cffi" },
|
||||
{ name = "pyexecjs" },
|
||||
{ name = "requests" },
|
||||
]
|
||||
|
||||
[package.metadata]
|
||||
requires-dist = [
|
||||
{ name = "curl-cffi", specifier = ">=0.14.0" },
|
||||
{ name = "pyexecjs", specifier = ">=1.5.1" },
|
||||
{ name = "requests", specifier = ">=2.32.5" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "certifi"
|
||||
version = "2026.1.4"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/e0/2d/a891ca51311197f6ad14a7ef42e2399f36cf2f9bd44752b3dc4eab60fdc5/certifi-2026.1.4.tar.gz", hash = "sha256:ac726dd470482006e014ad384921ed6438c457018f4b3d204aea4281258b2120", size = 154268, upload-time = "2026-01-04T02:42:41.825Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/e6/ad/3cc14f097111b4de0040c83a525973216457bbeeb63739ef1ed275c1c021/certifi-2026.1.4-py3-none-any.whl", hash = "sha256:9943707519e4add1115f44c2bc244f782c0249876bf51b6599fee1ffbedd685c", size = 152900, upload-time = "2026-01-04T02:42:40.15Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cffi"
|
||||
version = "2.0.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "pycparser", marker = "implementation_name != 'PyPy'" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/eb/56/b1ba7935a17738ae8453301356628e8147c79dbb825bcbc73dc7401f9846/cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529", size = 523588, upload-time = "2025-09-08T23:24:04.541Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/ea/47/4f61023ea636104d4f16ab488e268b93008c3d0bb76893b1b31db1f96802/cffi-2.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6d02d6655b0e54f54c4ef0b94eb6be0607b70853c45ce98bd278dc7de718be5d", size = 185271, upload-time = "2025-09-08T23:22:44.795Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/df/a2/781b623f57358e360d62cdd7a8c681f074a71d445418a776eef0aadb4ab4/cffi-2.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8eca2a813c1cb7ad4fb74d368c2ffbbb4789d377ee5bb8df98373c2cc0dee76c", size = 181048, upload-time = "2025-09-08T23:22:45.938Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ff/df/a4f0fbd47331ceeba3d37c2e51e9dfc9722498becbeec2bd8bc856c9538a/cffi-2.0.0-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:21d1152871b019407d8ac3985f6775c079416c282e431a4da6afe7aefd2bccbe", size = 212529, upload-time = "2025-09-08T23:22:47.349Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d5/72/12b5f8d3865bf0f87cf1404d8c374e7487dcf097a1c91c436e72e6badd83/cffi-2.0.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b21e08af67b8a103c71a250401c78d5e0893beff75e28c53c98f4de42f774062", size = 220097, upload-time = "2025-09-08T23:22:48.677Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c2/95/7a135d52a50dfa7c882ab0ac17e8dc11cec9d55d2c18dda414c051c5e69e/cffi-2.0.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:1e3a615586f05fc4065a8b22b8152f0c1b00cdbc60596d187c2a74f9e3036e4e", size = 207983, upload-time = "2025-09-08T23:22:50.06Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/3a/c8/15cb9ada8895957ea171c62dc78ff3e99159ee7adb13c0123c001a2546c1/cffi-2.0.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:81afed14892743bbe14dacb9e36d9e0e504cd204e0b165062c488942b9718037", size = 206519, upload-time = "2025-09-08T23:22:51.364Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/78/2d/7fa73dfa841b5ac06c7b8855cfc18622132e365f5b81d02230333ff26e9e/cffi-2.0.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3e17ed538242334bf70832644a32a7aae3d83b57567f9fd60a26257e992b79ba", size = 219572, upload-time = "2025-09-08T23:22:52.902Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/07/e0/267e57e387b4ca276b90f0434ff88b2c2241ad72b16d31836adddfd6031b/cffi-2.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3925dd22fa2b7699ed2617149842d2e6adde22b262fcbfada50e3d195e4b3a94", size = 222963, upload-time = "2025-09-08T23:22:54.518Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b6/75/1f2747525e06f53efbd878f4d03bac5b859cbc11c633d0fb81432d98a795/cffi-2.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2c8f814d84194c9ea681642fd164267891702542f028a15fc97d4674b6206187", size = 221361, upload-time = "2025-09-08T23:22:55.867Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/7b/2b/2b6435f76bfeb6bbf055596976da087377ede68df465419d192acf00c437/cffi-2.0.0-cp312-cp312-win32.whl", hash = "sha256:da902562c3e9c550df360bfa53c035b2f241fed6d9aef119048073680ace4a18", size = 172932, upload-time = "2025-09-08T23:22:57.188Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f8/ed/13bd4418627013bec4ed6e54283b1959cf6db888048c7cf4b4c3b5b36002/cffi-2.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:da68248800ad6320861f129cd9c1bf96ca849a2771a59e0344e88681905916f5", size = 183557, upload-time = "2025-09-08T23:22:58.351Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/95/31/9f7f93ad2f8eff1dbc1c3656d7ca5bfd8fb52c9d786b4dcf19b2d02217fa/cffi-2.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:4671d9dd5ec934cb9a73e7ee9676f9362aba54f7f34910956b84d727b0d73fb6", size = 177762, upload-time = "2025-09-08T23:22:59.668Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/4b/8d/a0a47a0c9e413a658623d014e91e74a50cdd2c423f7ccfd44086ef767f90/cffi-2.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:00bdf7acc5f795150faa6957054fbbca2439db2f775ce831222b66f192f03beb", size = 185230, upload-time = "2025-09-08T23:23:00.879Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/4a/d2/a6c0296814556c68ee32009d9c2ad4f85f2707cdecfd7727951ec228005d/cffi-2.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:45d5e886156860dc35862657e1494b9bae8dfa63bf56796f2fb56e1679fc0bca", size = 181043, upload-time = "2025-09-08T23:23:02.231Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b0/1e/d22cc63332bd59b06481ceaac49d6c507598642e2230f201649058a7e704/cffi-2.0.0-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:07b271772c100085dd28b74fa0cd81c8fb1a3ba18b21e03d7c27f3436a10606b", size = 212446, upload-time = "2025-09-08T23:23:03.472Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a9/f5/a2c23eb03b61a0b8747f211eb716446c826ad66818ddc7810cc2cc19b3f2/cffi-2.0.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d48a880098c96020b02d5a1f7d9251308510ce8858940e6fa99ece33f610838b", size = 220101, upload-time = "2025-09-08T23:23:04.792Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f2/7f/e6647792fc5850d634695bc0e6ab4111ae88e89981d35ac269956605feba/cffi-2.0.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f93fd8e5c8c0a4aa1f424d6173f14a892044054871c771f8566e4008eaa359d2", size = 207948, upload-time = "2025-09-08T23:23:06.127Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/cb/1e/a5a1bd6f1fb30f22573f76533de12a00bf274abcdc55c8edab639078abb6/cffi-2.0.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:dd4f05f54a52fb558f1ba9f528228066954fee3ebe629fc1660d874d040ae5a3", size = 206422, upload-time = "2025-09-08T23:23:07.753Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/98/df/0a1755e750013a2081e863e7cd37e0cdd02664372c754e5560099eb7aa44/cffi-2.0.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c8d3b5532fc71b7a77c09192b4a5a200ea992702734a2e9279a37f2478236f26", size = 219499, upload-time = "2025-09-08T23:23:09.648Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/50/e1/a969e687fcf9ea58e6e2a928ad5e2dd88cc12f6f0ab477e9971f2309b57c/cffi-2.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d9b29c1f0ae438d5ee9acb31cadee00a58c46cc9c0b2f9038c6b0b3470877a8c", size = 222928, upload-time = "2025-09-08T23:23:10.928Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/36/54/0362578dd2c9e557a28ac77698ed67323ed5b9775ca9d3fe73fe191bb5d8/cffi-2.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6d50360be4546678fc1b79ffe7a66265e28667840010348dd69a314145807a1b", size = 221302, upload-time = "2025-09-08T23:23:12.42Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/eb/6d/bf9bda840d5f1dfdbf0feca87fbdb64a918a69bca42cfa0ba7b137c48cb8/cffi-2.0.0-cp313-cp313-win32.whl", hash = "sha256:74a03b9698e198d47562765773b4a8309919089150a0bb17d829ad7b44b60d27", size = 172909, upload-time = "2025-09-08T23:23:14.32Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/37/18/6519e1ee6f5a1e579e04b9ddb6f1676c17368a7aba48299c3759bbc3c8b3/cffi-2.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:19f705ada2530c1167abacb171925dd886168931e0a7b78f5bffcae5c6b5be75", size = 183402, upload-time = "2025-09-08T23:23:15.535Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/cb/0e/02ceeec9a7d6ee63bb596121c2c8e9b3a9e150936f4fbef6ca1943e6137c/cffi-2.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:256f80b80ca3853f90c21b23ee78cd008713787b1b1e93eae9f3d6a7134abd91", size = 177780, upload-time = "2025-09-08T23:23:16.761Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/92/c4/3ce07396253a83250ee98564f8d7e9789fab8e58858f35d07a9a2c78de9f/cffi-2.0.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:fc33c5141b55ed366cfaad382df24fe7dcbc686de5be719b207bb248e3053dc5", size = 185320, upload-time = "2025-09-08T23:23:18.087Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/59/dd/27e9fa567a23931c838c6b02d0764611c62290062a6d4e8ff7863daf9730/cffi-2.0.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c654de545946e0db659b3400168c9ad31b5d29593291482c43e3564effbcee13", size = 181487, upload-time = "2025-09-08T23:23:19.622Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d6/43/0e822876f87ea8a4ef95442c3d766a06a51fc5298823f884ef87aaad168c/cffi-2.0.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:24b6f81f1983e6df8db3adc38562c83f7d4a0c36162885ec7f7b77c7dcbec97b", size = 220049, upload-time = "2025-09-08T23:23:20.853Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b4/89/76799151d9c2d2d1ead63c2429da9ea9d7aac304603de0c6e8764e6e8e70/cffi-2.0.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:12873ca6cb9b0f0d3a0da705d6086fe911591737a59f28b7936bdfed27c0d47c", size = 207793, upload-time = "2025-09-08T23:23:22.08Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/bb/dd/3465b14bb9e24ee24cb88c9e3730f6de63111fffe513492bf8c808a3547e/cffi-2.0.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:d9b97165e8aed9272a6bb17c01e3cc5871a594a446ebedc996e2397a1c1ea8ef", size = 206300, upload-time = "2025-09-08T23:23:23.314Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/47/d9/d83e293854571c877a92da46fdec39158f8d7e68da75bf73581225d28e90/cffi-2.0.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:afb8db5439b81cf9c9d0c80404b60c3cc9c3add93e114dcae767f1477cb53775", size = 219244, upload-time = "2025-09-08T23:23:24.541Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/2b/0f/1f177e3683aead2bb00f7679a16451d302c436b5cbf2505f0ea8146ef59e/cffi-2.0.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:737fe7d37e1a1bffe70bd5754ea763a62a066dc5913ca57e957824b72a85e205", size = 222828, upload-time = "2025-09-08T23:23:26.143Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c6/0f/cafacebd4b040e3119dcb32fed8bdef8dfe94da653155f9d0b9dc660166e/cffi-2.0.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:38100abb9d1b1435bc4cc340bb4489635dc2f0da7456590877030c9b3d40b0c1", size = 220926, upload-time = "2025-09-08T23:23:27.873Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/3e/aa/df335faa45b395396fcbc03de2dfcab242cd61a9900e914fe682a59170b1/cffi-2.0.0-cp314-cp314-win32.whl", hash = "sha256:087067fa8953339c723661eda6b54bc98c5625757ea62e95eb4898ad5e776e9f", size = 175328, upload-time = "2025-09-08T23:23:44.61Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/bb/92/882c2d30831744296ce713f0feb4c1cd30f346ef747b530b5318715cc367/cffi-2.0.0-cp314-cp314-win_amd64.whl", hash = "sha256:203a48d1fb583fc7d78a4c6655692963b860a417c0528492a6bc21f1aaefab25", size = 185650, upload-time = "2025-09-08T23:23:45.848Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/9f/2c/98ece204b9d35a7366b5b2c6539c350313ca13932143e79dc133ba757104/cffi-2.0.0-cp314-cp314-win_arm64.whl", hash = "sha256:dbd5c7a25a7cb98f5ca55d258b103a2054f859a46ae11aaf23134f9cc0d356ad", size = 180687, upload-time = "2025-09-08T23:23:47.105Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/3e/61/c768e4d548bfa607abcda77423448df8c471f25dbe64fb2ef6d555eae006/cffi-2.0.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:9a67fc9e8eb39039280526379fb3a70023d77caec1852002b4da7e8b270c4dd9", size = 188773, upload-time = "2025-09-08T23:23:29.347Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/2c/ea/5f76bce7cf6fcd0ab1a1058b5af899bfbef198bea4d5686da88471ea0336/cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7a66c7204d8869299919db4d5069a82f1561581af12b11b3c9f48c584eb8743d", size = 185013, upload-time = "2025-09-08T23:23:30.63Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/be/b4/c56878d0d1755cf9caa54ba71e5d049479c52f9e4afc230f06822162ab2f/cffi-2.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7cc09976e8b56f8cebd752f7113ad07752461f48a58cbba644139015ac24954c", size = 221593, upload-time = "2025-09-08T23:23:31.91Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e0/0d/eb704606dfe8033e7128df5e90fee946bbcb64a04fcdaa97321309004000/cffi-2.0.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:92b68146a71df78564e4ef48af17551a5ddd142e5190cdf2c5624d0c3ff5b2e8", size = 209354, upload-time = "2025-09-08T23:23:33.214Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d8/19/3c435d727b368ca475fb8742ab97c9cb13a0de600ce86f62eab7fa3eea60/cffi-2.0.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:b1e74d11748e7e98e2f426ab176d4ed720a64412b6a15054378afdb71e0f37dc", size = 208480, upload-time = "2025-09-08T23:23:34.495Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d0/44/681604464ed9541673e486521497406fadcc15b5217c3e326b061696899a/cffi-2.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:28a3a209b96630bca57cce802da70c266eb08c6e97e5afd61a75611ee6c64592", size = 221584, upload-time = "2025-09-08T23:23:36.096Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/25/8e/342a504ff018a2825d395d44d63a767dd8ebc927ebda557fecdaca3ac33a/cffi-2.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:7553fb2090d71822f02c629afe6042c299edf91ba1bf94951165613553984512", size = 224443, upload-time = "2025-09-08T23:23:37.328Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e1/5e/b666bacbbc60fbf415ba9988324a132c9a7a0448a9a8f125074671c0f2c3/cffi-2.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6c6c373cfc5c83a975506110d17457138c8c63016b563cc9ed6e056a82f13ce4", size = 223437, upload-time = "2025-09-08T23:23:38.945Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a0/1d/ec1a60bd1a10daa292d3cd6bb0b359a81607154fb8165f3ec95fe003b85c/cffi-2.0.0-cp314-cp314t-win32.whl", hash = "sha256:1fc9ea04857caf665289b7a75923f2c6ed559b8298a1b8c49e59f7dd95c8481e", size = 180487, upload-time = "2025-09-08T23:23:40.423Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/bf/41/4c1168c74fac325c0c8156f04b6749c8b6a8f405bbf91413ba088359f60d/cffi-2.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:d68b6cef7827e8641e8ef16f4494edda8b36104d79773a334beaa1e3521430f6", size = 191726, upload-time = "2025-09-08T23:23:41.742Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ae/3a/dbeec9d1ee0844c679f6bb5d6ad4e9f198b1224f4e7a32825f47f6192b0c/cffi-2.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:0a1527a803f0a659de1af2e1fd700213caba79377e27e4693648c2923da066f9", size = 184195, upload-time = "2025-09-08T23:23:43.004Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "charset-normalizer"
|
||||
version = "3.4.4"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/13/69/33ddede1939fdd074bce5434295f38fae7136463422fe4fd3e0e89b98062/charset_normalizer-3.4.4.tar.gz", hash = "sha256:94537985111c35f28720e43603b8e7b43a6ecfb2ce1d3058bbe955b73404e21a", size = 129418, upload-time = "2025-10-14T04:42:32.879Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/f3/85/1637cd4af66fa687396e757dec650f28025f2a2f5a5531a3208dc0ec43f2/charset_normalizer-3.4.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0a98e6759f854bd25a58a73fa88833fba3b7c491169f86ce1180c948ab3fd394", size = 208425, upload-time = "2025-10-14T04:40:53.353Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/9d/6a/04130023fef2a0d9c62d0bae2649b69f7b7d8d24ea5536feef50551029df/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b5b290ccc2a263e8d185130284f8501e3e36c5e02750fc6b6bdeb2e9e96f1e25", size = 148162, upload-time = "2025-10-14T04:40:54.558Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/78/29/62328d79aa60da22c9e0b9a66539feae06ca0f5a4171ac4f7dc285b83688/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:74bb723680f9f7a6234dcf67aea57e708ec1fbdf5699fb91dfd6f511b0a320ef", size = 144558, upload-time = "2025-10-14T04:40:55.677Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/86/bb/b32194a4bf15b88403537c2e120b817c61cd4ecffa9b6876e941c3ee38fe/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f1e34719c6ed0b92f418c7c780480b26b5d9c50349e9a9af7d76bf757530350d", size = 161497, upload-time = "2025-10-14T04:40:57.217Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/19/89/a54c82b253d5b9b111dc74aca196ba5ccfcca8242d0fb64146d4d3183ff1/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2437418e20515acec67d86e12bf70056a33abdacb5cb1655042f6538d6b085a8", size = 159240, upload-time = "2025-10-14T04:40:58.358Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c0/10/d20b513afe03acc89ec33948320a5544d31f21b05368436d580dec4e234d/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:11d694519d7f29d6cd09f6ac70028dba10f92f6cdd059096db198c283794ac86", size = 153471, upload-time = "2025-10-14T04:40:59.468Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/61/fa/fbf177b55bdd727010f9c0a3c49eefa1d10f960e5f09d1d887bf93c2e698/charset_normalizer-3.4.4-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:ac1c4a689edcc530fc9d9aa11f5774b9e2f33f9a0c6a57864e90908f5208d30a", size = 150864, upload-time = "2025-10-14T04:41:00.623Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/05/12/9fbc6a4d39c0198adeebbde20b619790e9236557ca59fc40e0e3cebe6f40/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:21d142cc6c0ec30d2efee5068ca36c128a30b0f2c53c1c07bd78cb6bc1d3be5f", size = 150647, upload-time = "2025-10-14T04:41:01.754Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ad/1f/6a9a593d52e3e8c5d2b167daf8c6b968808efb57ef4c210acb907c365bc4/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:5dbe56a36425d26d6cfb40ce79c314a2e4dd6211d51d6d2191c00bed34f354cc", size = 145110, upload-time = "2025-10-14T04:41:03.231Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/30/42/9a52c609e72471b0fc54386dc63c3781a387bb4fe61c20231a4ebcd58bdd/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:5bfbb1b9acf3334612667b61bd3002196fe2a1eb4dd74d247e0f2a4d50ec9bbf", size = 162839, upload-time = "2025-10-14T04:41:04.715Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c4/5b/c0682bbf9f11597073052628ddd38344a3d673fda35a36773f7d19344b23/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:d055ec1e26e441f6187acf818b73564e6e6282709e9bcb5b63f5b23068356a15", size = 150667, upload-time = "2025-10-14T04:41:05.827Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e4/24/a41afeab6f990cf2daf6cb8c67419b63b48cf518e4f56022230840c9bfb2/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:af2d8c67d8e573d6de5bc30cdb27e9b95e49115cd9baad5ddbd1a6207aaa82a9", size = 160535, upload-time = "2025-10-14T04:41:06.938Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/2a/e5/6a4ce77ed243c4a50a1fecca6aaaab419628c818a49434be428fe24c9957/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:780236ac706e66881f3b7f2f32dfe90507a09e67d1d454c762cf642e6e1586e0", size = 154816, upload-time = "2025-10-14T04:41:08.101Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a8/ef/89297262b8092b312d29cdb2517cb1237e51db8ecef2e9af5edbe7b683b1/charset_normalizer-3.4.4-cp312-cp312-win32.whl", hash = "sha256:5833d2c39d8896e4e19b689ffc198f08ea58116bee26dea51e362ecc7cd3ed26", size = 99694, upload-time = "2025-10-14T04:41:09.23Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/3d/2d/1e5ed9dd3b3803994c155cd9aacb60c82c331bad84daf75bcb9c91b3295e/charset_normalizer-3.4.4-cp312-cp312-win_amd64.whl", hash = "sha256:a79cfe37875f822425b89a82333404539ae63dbdddf97f84dcbc3d339aae9525", size = 107131, upload-time = "2025-10-14T04:41:10.467Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d0/d9/0ed4c7098a861482a7b6a95603edce4c0d9db2311af23da1fb2b75ec26fc/charset_normalizer-3.4.4-cp312-cp312-win_arm64.whl", hash = "sha256:376bec83a63b8021bb5c8ea75e21c4ccb86e7e45ca4eb81146091b56599b80c3", size = 100390, upload-time = "2025-10-14T04:41:11.915Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/97/45/4b3a1239bbacd321068ea6e7ac28875b03ab8bc0aa0966452db17cd36714/charset_normalizer-3.4.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:e1f185f86a6f3403aa2420e815904c67b2f9ebc443f045edd0de921108345794", size = 208091, upload-time = "2025-10-14T04:41:13.346Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/7d/62/73a6d7450829655a35bb88a88fca7d736f9882a27eacdca2c6d505b57e2e/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b39f987ae8ccdf0d2642338faf2abb1862340facc796048b604ef14919e55ed", size = 147936, upload-time = "2025-10-14T04:41:14.461Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/89/c5/adb8c8b3d6625bef6d88b251bbb0d95f8205831b987631ab0c8bb5d937c2/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3162d5d8ce1bb98dd51af660f2121c55d0fa541b46dff7bb9b9f86ea1d87de72", size = 144180, upload-time = "2025-10-14T04:41:15.588Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/91/ed/9706e4070682d1cc219050b6048bfd293ccf67b3d4f5a4f39207453d4b99/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:81d5eb2a312700f4ecaa977a8235b634ce853200e828fbadf3a9c50bab278328", size = 161346, upload-time = "2025-10-14T04:41:16.738Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d5/0d/031f0d95e4972901a2f6f09ef055751805ff541511dc1252ba3ca1f80cf5/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5bd2293095d766545ec1a8f612559f6b40abc0eb18bb2f5d1171872d34036ede", size = 158874, upload-time = "2025-10-14T04:41:17.923Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f5/83/6ab5883f57c9c801ce5e5677242328aa45592be8a00644310a008d04f922/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a8a8b89589086a25749f471e6a900d3f662d1d3b6e2e59dcecf787b1cc3a1894", size = 153076, upload-time = "2025-10-14T04:41:19.106Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/75/1e/5ff781ddf5260e387d6419959ee89ef13878229732732ee73cdae01800f2/charset_normalizer-3.4.4-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bc7637e2f80d8530ee4a78e878bce464f70087ce73cf7c1caf142416923b98f1", size = 150601, upload-time = "2025-10-14T04:41:20.245Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d7/57/71be810965493d3510a6ca79b90c19e48696fb1ff964da319334b12677f0/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f8bf04158c6b607d747e93949aa60618b61312fe647a6369f88ce2ff16043490", size = 150376, upload-time = "2025-10-14T04:41:21.398Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e5/d5/c3d057a78c181d007014feb7e9f2e65905a6c4ef182c0ddf0de2924edd65/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:554af85e960429cf30784dd47447d5125aaa3b99a6f0683589dbd27e2f45da44", size = 144825, upload-time = "2025-10-14T04:41:22.583Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e6/8c/d0406294828d4976f275ffbe66f00266c4b3136b7506941d87c00cab5272/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:74018750915ee7ad843a774364e13a3db91682f26142baddf775342c3f5b1133", size = 162583, upload-time = "2025-10-14T04:41:23.754Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d7/24/e2aa1f18c8f15c4c0e932d9287b8609dd30ad56dbe41d926bd846e22fb8d/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:c0463276121fdee9c49b98908b3a89c39be45d86d1dbaa22957e38f6321d4ce3", size = 150366, upload-time = "2025-10-14T04:41:25.27Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e4/5b/1e6160c7739aad1e2df054300cc618b06bf784a7a164b0f238360721ab86/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:362d61fd13843997c1c446760ef36f240cf81d3ebf74ac62652aebaf7838561e", size = 160300, upload-time = "2025-10-14T04:41:26.725Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/7a/10/f882167cd207fbdd743e55534d5d9620e095089d176d55cb22d5322f2afd/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9a26f18905b8dd5d685d6d07b0cdf98a79f3c7a918906af7cc143ea2e164c8bc", size = 154465, upload-time = "2025-10-14T04:41:28.322Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/89/66/c7a9e1b7429be72123441bfdbaf2bc13faab3f90b933f664db506dea5915/charset_normalizer-3.4.4-cp313-cp313-win32.whl", hash = "sha256:9b35f4c90079ff2e2edc5b26c0c77925e5d2d255c42c74fdb70fb49b172726ac", size = 99404, upload-time = "2025-10-14T04:41:29.95Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c4/26/b9924fa27db384bdcd97ab83b4f0a8058d96ad9626ead570674d5e737d90/charset_normalizer-3.4.4-cp313-cp313-win_amd64.whl", hash = "sha256:b435cba5f4f750aa6c0a0d92c541fb79f69a387c91e61f1795227e4ed9cece14", size = 107092, upload-time = "2025-10-14T04:41:31.188Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/af/8f/3ed4bfa0c0c72a7ca17f0380cd9e4dd842b09f664e780c13cff1dcf2ef1b/charset_normalizer-3.4.4-cp313-cp313-win_arm64.whl", hash = "sha256:542d2cee80be6f80247095cc36c418f7bddd14f4a6de45af91dfad36d817bba2", size = 100408, upload-time = "2025-10-14T04:41:32.624Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/2a/35/7051599bd493e62411d6ede36fd5af83a38f37c4767b92884df7301db25d/charset_normalizer-3.4.4-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:da3326d9e65ef63a817ecbcc0df6e94463713b754fe293eaa03da99befb9a5bd", size = 207746, upload-time = "2025-10-14T04:41:33.773Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/10/9a/97c8d48ef10d6cd4fcead2415523221624bf58bcf68a802721a6bc807c8f/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8af65f14dc14a79b924524b1e7fffe304517b2bff5a58bf64f30b98bbc5079eb", size = 147889, upload-time = "2025-10-14T04:41:34.897Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/10/bf/979224a919a1b606c82bd2c5fa49b5c6d5727aa47b4312bb27b1734f53cd/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:74664978bb272435107de04e36db5a9735e78232b85b77d45cfb38f758efd33e", size = 143641, upload-time = "2025-10-14T04:41:36.116Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ba/33/0ad65587441fc730dc7bd90e9716b30b4702dc7b617e6ba4997dc8651495/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:752944c7ffbfdd10c074dc58ec2d5a8a4cd9493b314d367c14d24c17684ddd14", size = 160779, upload-time = "2025-10-14T04:41:37.229Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/67/ed/331d6b249259ee71ddea93f6f2f0a56cfebd46938bde6fcc6f7b9a3d0e09/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d1f13550535ad8cff21b8d757a3257963e951d96e20ec82ab44bc64aeb62a191", size = 159035, upload-time = "2025-10-14T04:41:38.368Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/67/ff/f6b948ca32e4f2a4576aa129d8bed61f2e0543bf9f5f2b7fc3758ed005c9/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ecaae4149d99b1c9e7b88bb03e3221956f68fd6d50be2ef061b2381b61d20838", size = 152542, upload-time = "2025-10-14T04:41:39.862Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/16/85/276033dcbcc369eb176594de22728541a925b2632f9716428c851b149e83/charset_normalizer-3.4.4-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:cb6254dc36b47a990e59e1068afacdcd02958bdcce30bb50cc1700a8b9d624a6", size = 149524, upload-time = "2025-10-14T04:41:41.319Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/9e/f2/6a2a1f722b6aba37050e626530a46a68f74e63683947a8acff92569f979a/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c8ae8a0f02f57a6e61203a31428fa1d677cbe50c93622b4149d5c0f319c1d19e", size = 150395, upload-time = "2025-10-14T04:41:42.539Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/60/bb/2186cb2f2bbaea6338cad15ce23a67f9b0672929744381e28b0592676824/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:47cc91b2f4dd2833fddaedd2893006b0106129d4b94fdb6af1f4ce5a9965577c", size = 143680, upload-time = "2025-10-14T04:41:43.661Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/7d/a5/bf6f13b772fbb2a90360eb620d52ed8f796f3c5caee8398c3b2eb7b1c60d/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:82004af6c302b5d3ab2cfc4cc5f29db16123b1a8417f2e25f9066f91d4411090", size = 162045, upload-time = "2025-10-14T04:41:44.821Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/df/c5/d1be898bf0dc3ef9030c3825e5d3b83f2c528d207d246cbabe245966808d/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:2b7d8f6c26245217bd2ad053761201e9f9680f8ce52f0fcd8d0755aeae5b2152", size = 149687, upload-time = "2025-10-14T04:41:46.442Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a5/42/90c1f7b9341eef50c8a1cb3f098ac43b0508413f33affd762855f67a410e/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:799a7a5e4fb2d5898c60b640fd4981d6a25f1c11790935a44ce38c54e985f828", size = 160014, upload-time = "2025-10-14T04:41:47.631Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/76/be/4d3ee471e8145d12795ab655ece37baed0929462a86e72372fd25859047c/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:99ae2cffebb06e6c22bdc25801d7b30f503cc87dbd283479e7b606f70aff57ec", size = 154044, upload-time = "2025-10-14T04:41:48.81Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b0/6f/8f7af07237c34a1defe7defc565a9bc1807762f672c0fde711a4b22bf9c0/charset_normalizer-3.4.4-cp314-cp314-win32.whl", hash = "sha256:f9d332f8c2a2fcbffe1378594431458ddbef721c1769d78e2cbc06280d8155f9", size = 99940, upload-time = "2025-10-14T04:41:49.946Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/4b/51/8ade005e5ca5b0d80fb4aff72a3775b325bdc3d27408c8113811a7cbe640/charset_normalizer-3.4.4-cp314-cp314-win_amd64.whl", hash = "sha256:8a6562c3700cce886c5be75ade4a5db4214fda19fede41d9792d100288d8f94c", size = 107104, upload-time = "2025-10-14T04:41:51.051Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/da/5f/6b8f83a55bb8278772c5ae54a577f3099025f9ade59d0136ac24a0df4bde/charset_normalizer-3.4.4-cp314-cp314-win_arm64.whl", hash = "sha256:de00632ca48df9daf77a2c65a484531649261ec9f25489917f09e455cb09ddb2", size = 100743, upload-time = "2025-10-14T04:41:52.122Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/0a/4c/925909008ed5a988ccbb72dcc897407e5d6d3bd72410d69e051fc0c14647/charset_normalizer-3.4.4-py3-none-any.whl", hash = "sha256:7a32c560861a02ff789ad905a2fe94e3f840803362c84fecf1851cb4cf3dc37f", size = 53402, upload-time = "2025-10-14T04:42:31.76Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "curl-cffi"
|
||||
version = "0.14.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "certifi" },
|
||||
{ name = "cffi" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/9b/c9/0067d9a25ed4592b022d4558157fcdb6e123516083700786d38091688767/curl_cffi-0.14.0.tar.gz", hash = "sha256:5ffbc82e59f05008ec08ea432f0e535418823cda44178ee518906a54f27a5f0f", size = 162633, upload-time = "2025-12-16T03:25:07.931Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/aa/f0/0f21e9688eaac85e705537b3a87a5588d0cefb2f09d83e83e0e8be93aa99/curl_cffi-0.14.0-cp39-abi3-macosx_14_0_arm64.whl", hash = "sha256:e35e89c6a69872f9749d6d5fda642ed4fc159619329e99d577d0104c9aad5893", size = 3087277, upload-time = "2025-12-16T03:24:49.607Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ba/a3/0419bd48fce5b145cb6a2344c6ac17efa588f5b0061f212c88e0723da026/curl_cffi-0.14.0-cp39-abi3-macosx_15_0_x86_64.whl", hash = "sha256:5945478cd28ad7dfb5c54473bcfb6743ee1d66554d57951fdf8fc0e7d8cf4e45", size = 5804650, upload-time = "2025-12-16T03:24:51.518Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e2/07/a238dd062b7841b8caa2fa8a359eb997147ff3161288f0dd46654d898b4d/curl_cffi-0.14.0-cp39-abi3-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c42e8fa3c667db9ccd2e696ee47adcd3cd5b0838d7282f3fc45f6c0ef3cfdfa7", size = 8231918, upload-time = "2025-12-16T03:24:52.862Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/7c/d2/ce907c9b37b5caf76ac08db40cc4ce3d9f94c5500db68a195af3513eacbc/curl_cffi-0.14.0-cp39-abi3-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:060fe2c99c41d3cb7f894de318ddf4b0301b08dca70453d769bd4e74b36b8483", size = 8654624, upload-time = "2025-12-16T03:24:54.579Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f2/ae/6256995b18c75e6ef76b30753a5109e786813aa79088b27c8eabb1ef85c9/curl_cffi-0.14.0-cp39-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:b158c41a25388690dd0d40b5bc38d1e0f512135f17fdb8029868cbc1993d2e5b", size = 8010654, upload-time = "2025-12-16T03:24:56.507Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/fb/10/ff64249e516b103cb762e0a9dca3ee0f04cf25e2a1d5d9838e0f1273d071/curl_cffi-0.14.0-cp39-abi3-manylinux_2_28_i686.whl", hash = "sha256:1439fbef3500fb723333c826adf0efb0e2e5065a703fb5eccce637a2250db34a", size = 7781969, upload-time = "2025-12-16T03:24:57.885Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/51/76/d6f7bb76c2d12811aa7ff16f5e17b678abdd1b357b9a8ac56310ceccabd5/curl_cffi-0.14.0-cp39-abi3-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e7176f2c2d22b542e3cf261072a81deb018cfa7688930f95dddef215caddb469", size = 7969133, upload-time = "2025-12-16T03:24:59.261Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/23/7c/cca39c0ed4e1772613d3cba13091c0e9d3b89365e84b9bf9838259a3cd8f/curl_cffi-0.14.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:03f21ade2d72978c2bb8670e9b6de5260e2755092b02d94b70b906813662998d", size = 9080167, upload-time = "2025-12-16T03:25:00.946Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/75/03/a942d7119d3e8911094d157598ae0169b1c6ca1bd3f27d7991b279bcc45b/curl_cffi-0.14.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:58ebf02de64ee5c95613209ddacb014c2d2f86298d7080c0a1c12ed876ee0690", size = 9520464, upload-time = "2025-12-16T03:25:02.922Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a2/77/78900e9b0833066d2274bda75cba426fdb4cef7fbf6a4f6a6ca447607bec/curl_cffi-0.14.0-cp39-abi3-win_amd64.whl", hash = "sha256:6e503f9a103f6ae7acfb3890c843b53ec030785a22ae7682a22cc43afb94123e", size = 1677416, upload-time = "2025-12-16T03:25:04.902Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/5c/7c/d2ba86b0b3e1e2830bd94163d047de122c69a8df03c5c7c36326c456ad82/curl_cffi-0.14.0-cp39-abi3-win_arm64.whl", hash = "sha256:2eed50a969201605c863c4c31269dfc3e0da52916086ac54553cfa353022425c", size = 1425067, upload-time = "2025-12-16T03:25:06.454Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "3.11"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/6f/6d/0703ccc57f3a7233505399edb88de3cbd678da106337b9fcde432b65ed60/idna-3.11.tar.gz", hash = "sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902", size = 194582, upload-time = "2025-10-12T14:55:20.501Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea", size = 71008, upload-time = "2025-10-12T14:55:18.883Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pycparser"
|
||||
version = "2.23"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/fe/cf/d2d3b9f5699fb1e4615c8e32ff220203e43b248e1dfcc6736ad9057731ca/pycparser-2.23.tar.gz", hash = "sha256:78816d4f24add8f10a06d6f05b4d424ad9e96cfebf68a4ddc99c65c0720d00c2", size = 173734, upload-time = "2025-09-09T13:23:47.91Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/a0/e3/59cd50310fc9b59512193629e1984c1f95e5c8ae6e5d8c69532ccc65a7fe/pycparser-2.23-py3-none-any.whl", hash = "sha256:e5c6e8d3fbad53479cab09ac03729e0a9faf2bee3db8208a550daf5af81a5934", size = 118140, upload-time = "2025-09-09T13:23:46.651Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pyexecjs"
|
||||
version = "1.5.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "six" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/ba/8e/aedef81641c8dca6fd0fb7294de5bed9c45f3397d67fddf755c1042c2642/PyExecJS-1.5.1.tar.gz", hash = "sha256:34cc1d070976918183ff7bdc0ad71f8157a891c92708c00c5fbbff7a769f505c", size = 13344, upload-time = "2018-01-18T04:33:55.126Z" }
|
||||
|
||||
[[package]]
|
||||
name = "requests"
|
||||
version = "2.32.5"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "certifi" },
|
||||
{ name = "charset-normalizer" },
|
||||
{ name = "idna" },
|
||||
{ name = "urllib3" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/c9/74/b3ff8e6c8446842c3f5c837e9c3dfcfe2018ea6ecef224c710c85ef728f4/requests-2.32.5.tar.gz", hash = "sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf", size = 134517, upload-time = "2025-08-18T20:46:02.573Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6", size = 64738, upload-time = "2025-08-18T20:46:00.542Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "six"
|
||||
version = "1.17.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031, upload-time = "2024-12-04T17:35:28.174Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "urllib3"
|
||||
version = "2.6.3"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/c7/24/5f1b3bdffd70275f6661c76461e25f024d5a38a46f04aaca912426a2b1d3/urllib3-2.6.3.tar.gz", hash = "sha256:1b62b6884944a57dbe321509ab94fd4d3b307075e0c2eae991ac71ee15ad38ed", size = 435556, upload-time = "2026-01-07T16:24:43.925Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl", hash = "sha256:bf272323e553dfb2e87d9bfd225ca7b0f467b919d7bbd355436d3fd37cb0acd4", size = 131584, upload-time = "2026-01-07T16:24:42.685Z" },
|
||||
]
|
||||
Reference in New Issue
Block a user