liumangmang 4f9acdc99c feat(auth-capture): full cookie bundle extraction + richer refresh-auth
Problem: Meow upstream uses Cloudflare, which sets cf_clearance + session
cookies that must all be sent together. The old code only captured a single
session-named cookie via a whitelist, discarding cf_clearance entirely, and
wrote back only 'name=value' instead of the full cookie string.

Changes:

auth_capture_service.py:
  - Add _cookie_matches_hostname(): hostname suffix matching supporting
    dot-prefixed domains (.saki.lat matches api.saki.lat)
  - Add _build_cookie_bundle(): collects ALL cookies matching the current
    page's hostname, returns complete 'name1=v1; name2=v2' string
  - _curate_candidates(): new 'cookie_bundle' candidate type (type=0 in sort,
    highest priority), carries cookie_count + cookie_names in extra fields
  - extract_all(): obtain real-time page URL from session.page.url and pass
    to _curate_candidates so cookie domain filtering is accurate
  - Sort order: cookie_bundle > cookie > bearer_token/api_key > credential
  - Fix bug in original JWT dedup check (was assigning instead of checking)

custom_pages.py:
  - Add logging import + logger
  - _pick_best_candidate(): cookie preferred_auth_type now tries cookie_bundle
    first, then single cookie; bearer/api_key use existing type_map logic
  - RefreshAuthResponse: add optional 'warning' field
  - refresh_auth(): handle ctype='cookie_bundle' same as 'cookie'; always
    write full candidate.value as cookie_string (works for both types)
  - Post-write validation: attempt get_available_groups with new credentials;
    on failure, still commit (lenient mode) but set warning message explaining
    cf_clearance IP-binding as the likely cause; success logs at INFO level

Tests (test_auth_capture.py, 19 cases):
  - _cookie_matches_hostname: exact, dot-prefix subdomain, empty domain,
    different domain, evil-subdomain partial match rejection
  - _build_cookie_bundle: cf_clearance included, cross-domain excluded,
    single cookie, empty value excluded, no cookies
  - _curate_candidates: bundle ranks first, value is full string, bundle
    beats single session cookie, bearer wins when no cookies, empty case,
    cookie_count/cookie_names in extra, session fallback preserved,
    new_api_user propagation to bundle

All 46 tests pass.
2026-06-02 09:32:23 +08:00

SmartUp — API 上游管理与 Webhook 通知系统

SmartUp 是一个独立的 Web 后台,用于管理多个 API 上游的分组倍率监听,并通过 Webhook(通用 JSON / 钉钉机器人)发送变更通知。

功能

  • 上游管理:支持 none / bearer / api_key / 邮箱密码 四种认证方式
  • 定时检测:每个上游独立配置检测间隔,APScheduler 后台运行
  • 倍率快照:检测变化后保存快照,diff 比对历史
  • Webhook 通知:支持通用 JSON 和钉钉机器人(带签名)
  • 通知日志:记录每次发送结果,支持筛选查看
  • 自定义页面:支持直接嵌入、代理模式、远程浏览器模式

技术栈

  • 后端:FastAPI + SQLite + APScheduler
  • 前端:Vue 3 + Element Plus + Vite
  • 部署:Docker Compose 单容器

快速部署

1. 准备配置文件

cp .env.example .env
# 编辑 .env,至少填写 ADMIN_PASSWORD 和 JWT_SECRET

2. 启动

docker compose up -d --build

首次启动时自动:

  • 创建 SQLite 数据库(./data/app.db
  • 初始化管理员账号

3. 访问

打开浏览器:http://localhost:8899

默认账号:.env 中配置的 ADMIN_EMAIL / ADMIN_PASSWORD

本地开发

后端

cd backend
python -m venv venv && source venv/bin/activate
pip install -r requirements.txt
playwright install chromium

# 创建 .env(可复制根目录的 .env.example
cat > .env << 'EOF'
ADMIN_EMAIL=admin@smartup.local
ADMIN_PASSWORD=dev123
JWT_SECRET=dev-secret
DATABASE_URL=sqlite:///./data/app.db
EOF

mkdir -p data
uvicorn app.main:app --reload --port 8000

前端

cd frontend
npm install
npm run dev   # 代理到 localhost:8000

数据备份

SQLite 数据库位于 ./data/app.db,直接复制即可备份:

WAL 模式说明:启用 WAL 后,备份前请先执行 checkpoint 将 WAL 合并入主库:

sqlite3 ./data/app.db "PRAGMA wal_checkpoint(TRUNCATE);"
cp ./data/app.db ./data/app.db.$(date +%Y%m%d)

环境变量

变量 说明 默认值
ADMIN_EMAIL 管理员邮箱 admin@smartup.local
ADMIN_PASSWORD 管理员密码(必填)
JWT_SECRET JWT 签名密钥 change-me-in-production
SERVER_PORT 宿主机端口 8899
TZ 时区 Asia/Shanghai
UNHEALTHY_THRESHOLD 连续失败多少次标记为异常 3
BROWSER_PROFILES_DIR 远程浏览器登录态/profile 存储目录 /app/data/browser-profiles
BROWSER_HEADLESS 远程浏览器是否无头运行 true

目录结构

SmartUp/
├── backend/          # FastAPI 应用
│   └── app/
│       ├── models/   # SQLAlchemy ORM
│       ├── schemas/  # Pydantic schemas
│       ├── routers/  # API 路由
│       ├── services/ # 业务逻辑(client/scheduler/webhook
│       └── utils/    # JWT / 钉钉签名
├── frontend/         # Vue 3 前端
│   └── src/
│       ├── views/    # 页面组件
│       ├── api/      # Axios 封装
│       └── stores/   # Pinia 状态
├── data/             # SQLite 数据目录(Docker volume
├── Dockerfile        # 多阶段构建
├── docker-compose.yml
└── .env.example
S
Description
No description provided
Readme 14 MiB
Languages
Python 64.3%
Vue 28.2%
TypeScript 3.3%
CSS 2.1%
JavaScript 1.1%
Other 1%