Metadata-Version: 2.4
Name: cookiecloud_decrypt
Version: 0.1.0
Summary: CookieCloud data decryption SDK — supports legacy and aes-128-cbc-fixed modes
Author-email: cky <cky@example.com>
License: MIT
Project-URL: Homepage, https://github.com/YOUR_USERNAME/cookiecloud_decrypt
Project-URL: Repository, https://github.com/YOUR_USERNAME/cookiecloud_decrypt
Keywords: cookiecloud,cookie,decrypt,web-scraping
Classifier: Development Status :: 4 - Beta
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Internet :: WWW/HTTP
Requires-Python: >=3.11
Description-Content-Type: text/markdown
Requires-Dist: pycryptodome>=3.19
Provides-Extra: dev
Requires-Dist: pytest>=8.0; extra == "dev"
Requires-Dist: pytest-vcr>=1.0; extra == "dev"
Requires-Dist: httpx>=0.27; extra == "dev"
Requires-Dist: python-dotenv>=1.0; extra == "dev"

# cookiecloud_decrypt

CookieCloud 数据解密 SDK，纯 Python，无其他运行时依赖。

支持两种加密模式：

- **aes-128-cbc-fixed**：新版 CookieCloud 服务器（MD5(key) + 零 IV）
- **legacy**：旧版使用（MD5 chain + Salted__ header，与 pycookiecloud 兼容）

## 安装

```bash
pip install cookiecloud_decrypt
```

## 快速开始

```python
from cookiecloud_decrypt import decrypt, to_playwright_cookies, to_cookie_str

# 1. 从 CookieCloud 服务端获取加密数据（任意 HTTP 库）
import httpx
resp = httpx.get(
    "https://your-server.com/get/YOUR_UUID",
    params={"password": "YOUR_PASSWORD"},
)
encrypted = resp.json()["encrypted"]

# 2. 解密（auto 模式自动识别格式）
data = decrypt(encrypted, uuid="YOUR_UUID", password="YOUR_PASSWORD")

# 3. 格式化输出
# Playwright add_cookies 格式
cookies = to_playwright_cookies(data, domains=[".example.com"])

# "k1=v1; k2=v2" 字符串格式
cookie_str = to_cookie_str(data, domain=".example.com", keys=["a1", "session"])
```

## API

### `decrypt(encrypted, uuid, password, mode="auto")`

解密 CookieCloud 服务端返回的加密数据。

| 参数 | 类型 | 说明 |
|------|------|------|
| `encrypted` | `str` | CookieCloud GET `/get/{uuid}` 返回的 `encrypted` 字段（base64） |
| `uuid` | `str` | CookieCloud UUID |
| `password` | `str` | CookieCloud 密码 |
| `mode` | `str` | 解密模式：`"auto"`（默认，自动检测）、`"legacy"`、`"aes-128-cbc-fixed"` |

**返回值**：解密后的 dict，结构为 `{"cookie_data": {域名: [CookieEntry, ...]}, "update_time": ...}`

**异常**：
- `InvalidKeyError` — UUID 或密码错误
- `CorruptedDataError` — 密文格式损坏

### `to_playwright_cookies(data, domains=None)`

导出为 Playwright `BrowserContext.add_cookies()` 所需格式。

```python
from playwright.async_api import async_playwright

cookies = to_playwright_cookies(data, domains=[".xiaohongshu.com"])
async with async_playwright() as p:
    ctx = await p.chromium.launch()
    await ctx.add_cookies(cookies)
```

### `to_cookie_str(data, domain, keys=None)`

导出为 `k1=v1; k2=v2` 格式的字符串。

```python
cookie_str = to_cookie_str(
    data,
    domain=".xiaohongshu.com",
    keys=["a1", "web_session"],
)
# → "a1=xxx; web_session=yyy"
```

### `to_cookie_dict(data, domains=None)`

导出为 `{域名: [CookieEntry, ...]}` 格式。

## 开发

```bash
# 安装
pip install -e ".[dev]"

# 运行测试
pytest tests/ -v

# 端到端测试（首次需要联网录制 cassette）
cp .env.example .env
# 填入真实 COOKIECLOUD_SERVER / COOKIECLOUD_UUID / COOKIECLOUD_PASSWORD
pytest tests/e2e_test.py -v --vcr-record=new_episodes
```

## 发布到 PyPI

```bash
# 1. 安装构建工具
pip install build twine

# 2. 构建 wheel 和 sdist
python -m build

# 3. 上传到 TestPyPI（先测）
twine upload --repository testpypi dist/*

# 4. 上传到正式 PyPI
twine upload dist/*
```

发布后外部用户直接 `pip install cookiecloud_decrypt` 即可使用。
