Files
cookie/frontend/cookie_cloud_client.py

127 lines
4.5 KiB
Python

"""
Cookie Cloud 客户端(独立前端使用)
"""
import json
import hashlib
import logging
import requests
from base64 import b64decode
logger = logging.getLogger('cookie_cloud')
try:
from Cryptodome.Cipher import AES
from Cryptodome.Util.Padding import unpad
except ImportError:
from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad
def cookie_decrypt(uuid: str, encrypted_b64: str, password: str) -> dict:
"""解密Cookie Cloud数据"""
the_key = hashlib.md5(f"{uuid}-{password}".encode()).hexdigest()[:16].encode()
encrypted_data = b64decode(encrypted_b64)
logger.info("尝试AES-ECB解密...")
try:
cipher = AES.new(the_key, AES.MODE_ECB)
decrypted = cipher.decrypt(encrypted_data)
result = unpad(decrypted, AES.block_size)
data = json.loads(result.decode('utf-8'))
logger.info("AES-ECB解密成功")
return data
except Exception as e:
logger.info(f"AES-ECB解密失败: {e},尝试Salted__格式...")
pass
if encrypted_data[:8] == b'Salted__':
logger.info("检测到Salted__格式,尝试CBC解密...")
salt = encrypted_data[8:16]
ciphertext = encrypted_data[16:]
logger.info(f"Salt: {salt.hex()}")
d = [b'']
while len(b''.join(d)) < 48:
d.append(hashlib.md5(d[-1] + the_key + salt).digest())
key_iv = b''.join(d)
cipher = AES.new(key_iv[:32], AES.MODE_CBC, key_iv[32:48])
decrypted = unpad(cipher.decrypt(ciphertext), AES.block_size)
data = json.loads(decrypted.decode('utf-8'))
logger.info("CBC解密成功")
return data
logger.error("所有解密方式均失败")
raise ValueError('无法解密Cookie数据')
def download_cookies(api_url: str, uuid: str, password: str) -> dict:
"""从Cookie Cloud服务器下载并解密Cookie"""
api_url = api_url.rstrip('/')
url = f"{api_url}/get/{uuid}"
logger.info(f"[1/3] 请求Cookie Cloud: {url}")
logger.info(f"[1/3] UUID: {uuid}")
response = requests.get(url, params={'password': password}, timeout=10)
response.raise_for_status()
result = response.json()
logger.info(f"[1/3] HTTP状态码: {response.status_code}")
logger.info(f"[1/3] 返回数据keys: {list(result.keys())}")
logger.info(f"[1/3] 返回数据大小: {len(json.dumps(result))} bytes")
if isinstance(result, dict) and result.get('encrypted'):
logger.info("[2/3] 检测到加密数据,开始解密...")
result = cookie_decrypt(uuid, result['encrypted'], password)
logger.info(f"[2/3] 解密完成,数据类型: {type(result)}")
if isinstance(result, dict):
logger.info(f"[2/3] Cookie数据包含域名: {list(result.keys())}")
if isinstance(result, dict) and 'cookie_data' in result:
cookies_data = result.get('cookie_data', {})
logger.info(f"[3/3] 新版CookieCloud格式,提取cookie_data")
logger.info(f"[3/3] cookie_data包含域名数: {len(cookies_data)}")
return cookies_data
logger.info(f"[3/3] 返回数据已处理完成")
return result
def get_cookies_for_domain(cookies_data: dict, domain: str) -> list:
"""提取指定域名对应的Cookie列表"""
result = []
matched_hosts = []
domain_parts = domain.lower().split('.')
for host, cookie_list in cookies_data.items():
host_clean = host.lower().lstrip('.')
domain_clean = domain.lower()
is_match = False
if host_clean == domain_clean:
is_match = True
elif host_clean.endswith('.' + domain_clean):
is_match = True
elif domain_clean.endswith('.' + host_clean):
is_match = True
if is_match:
matched_hosts.append(host)
if isinstance(cookie_list, list):
for cookie in cookie_list:
if cookie.get('name') and cookie.get('value'):
result.append({
'name': cookie['name'],
'value': cookie['value'],
'domain': cookie.get('domain', domain),
'path': cookie.get('path', '/')
})
logger.info(f"域名匹配结果: 目标={domain}, 匹配hosts={matched_hosts}")
logger.info(f"提取Cookie数量: {len(result)}")
if result:
cookie_names = [c['name'] for c in result[:5]]
logger.info(f"前5个Cookie名称: {cookie_names}")
return result