# K12 相关工具分析

本文基于仓库 `packages/K12/` 下实际子模块源码整理。子模块已初始化：

- `K12-Space-Automation`: `b941a443284401c6bc661eb82d708bd7b8269bce`
- `chatgpt-register-sub2api`: `6536613d6c50c5289339a08160b4d51136c86967`

## 总体定位

K12 工具集围绕同一目标：把邮箱账号变成可用于 K12 workspace 的 ChatGPT/OpenAI 账号，再把 token 或账号资料导出或写入 Sub2API/CPA。

通用链路：

```text
邮箱资源
  -> ChatGPT/OpenAI 注册或登录
  -> 获取个人 access token
  -> 对 K12 workspace 执行 request/accept
  -> 切换或刷新获得 K12/workspace token
  -> 写入 Sub2API 或导出 JSON
  -> 测活、修复、补号
```

## 工具清单

### 1. K12-Space-Automation

路径：`packages/K12/K12-Space-Automation/`

定位：本地 Web 控制台。它把邮箱池、K12 加入、Sub2API 入库、noRT 直入、AT 测活修复、自动补号、JSON 导出、任务日志集中在一个 Node/Vue 应用里。

关键文件：

- `README.md`: 功能和部署说明。
- `package.json`: 启动脚本，`npm run dev` 同时跑 API 和 Vite 前端，`npm run start` 跑构建后的本地服务。
- `src/App.vue`: Vue 控制台，包含任务列表、设置弹窗、邮箱导入、邮箱池、补号、测活、修复入口。
- `server/index.ts`: 核心后端。包含配置、邮箱池、任务调度、K12 workspace、Sub2API、动态 Gmail、AT 测活修复、数据导入导出。
- `codex_register/`: 底层注册、OAuth、邮箱、SMS、Sentinel、Sub2API、CPA 能力包。

运行入口：

```bash
cd packages/K12/K12-Space-Automation
npm install
npm run dev
```

普通运行：

```bash
npm run build
npm run start
```

默认端口：

- 开发前端：`5174`
- API/生产服务：`8796`

### 2. chatgpt-register-sub2api

路径：`packages/K12/chatgpt-register-sub2api/`

定位：轻量 Python CLI。重点是“注册 ChatGPT 账号 -> 加入 K12 workspace -> refresh/check -> 导出 Sub2API JSON”。不提供 Web 控制台，不直接调用 Sub2API 管理接口入库。

关键文件：

- `README.md`: 命令和流程说明。
- `pyproject.toml`: Python 包入口，命令为 `chatgpt-register`。
- `config.example.yaml`: Outlook 邮箱池、代理、注册数量、workspace、导出文件配置。
- `chatgpt_register_sub2api/cli.py`: CLI 子命令入口。
- `chatgpt_register_sub2api/pipeline.py`: 串联注册、进组、refresh/check、导出。
- `register/registrar.py`: OpenAI/Auth 注册流程。
- `workspace/joiner.py`: K12 workspace request/accept 请求。
- `export/sub2api.py`: Sub2API JSON bundle 构造。

安装入口：

```bash
cd packages/K12/chatgpt-register-sub2api
python3 -m venv .venv
source .venv/bin/activate
pip install -e .
chatgpt-register init
chatgpt-register run -n 10 -v
```

## K12-Space-Automation 工作逻辑

### 数据模型

后端核心类型在 `server/index.ts` 顶部：

- `AppConfig`: 端口、代理、workspace IDs、K12 route、并发、Sub2API、动态 Gmail、JSON 输出。
- `EmailRecord`: 邮箱池记录，保存邮箱、密码、接码方式、refresh token、运行状态、Sub2API 账号名、动态 Gmail 元数据。
- `K12Task`: 任务记录，保存邮箱、workspace IDs、运行开关、Sub2API 分组、AT、workspace 执行结果、日志、状态。
- `Sub2ApiRefillResult`: 自动补号检测结果。

运行时文件：

- `data/config.json`: 本地配置。
- `data/emails.json`: 邮箱池。
- `data/tasks.json`: 任务列表和日志。
- `data/sub2api-refill-history.json`: 补号历史。
- `json/`: 账号 JSON 输出目录。
- `pool_tokens.txt` 或配置中的 `tokenOut`: access token 输出。

### Web/API 流程

前端 `src/App.vue` 通过本地 API 操作后端：

- `GET /api/config`, `POST|PATCH /api/config`: 读写设置。
- `POST /api/emails/import`: 导入邮箱池。
- `POST /api/emails/split`: Gmail plus alias 分裂。
- `POST /api/tasks`: 创建 K12 任务。
- `GET /api/tasks`: 查询任务。
- `POST /api/tasks/{id}/cancel`: 取消任务。
- `POST /api/tasks/{id}/retry`: 重试任务。
- `POST /api/tasks/check-at`: 任务 AT 测活。
- `POST /api/tasks/repair-at`: 创建 AT 修复任务。
- `POST /api/sub2api/refill/start`: 手动触发补号。
- `GET /api/data/export`, `POST /api/data/import`: 本地数据包导出/导入。

### 任务创建

`createTasks()` 做这些事：

1. 从请求中的 `emailIds` 选邮箱；没有指定邮箱且开启动态 Gmail 时，临时租 Gmail。
2. 读取或覆盖 workspace IDs。
3. 决定 route：`request` 或 `accept`。
4. 决定是否执行 `runWorkspaceJoin`、`runSub2Api`、`sub2apiNoRtMode`。
5. 为每个邮箱创建 `K12Task`，状态置为 `queued`。
6. 调用 `scheduleTasks()` 按并发启动任务。

动态 Gmail 两种来源：

- SMSBower Gmail：支持余额、租邮箱、价格限制、Gmail fission 子任务、结束后释放。
- Emailnator：创建临时 Gmail，保存 session cookie、XSRF token、基线邮件 ID，轮询 OpenAI 验证码。

### 主任务 runTask()

`runTask()` 是 K12-Space-Automation 的主执行器。

主流程：

1. 找到邮箱记录；封号或缺邮箱则失败。
2. 创建 OpenAI client，按邮箱登录 ChatGPT Web。
3. 如果需要 K12 workspace，获取个人 access token 并记录。
4. 按配置进入三种路径：

#### 路径 A：Sub2API OAuth 入库

条件：`runSub2Api=true` 且 `sub2apiNoRtMode=false`。

流程：

1. 初始化 `Sub2ApiClient`。
2. 调用 `prepareOpenAiOAuth()` 获取 Sub2API OAuth URL。
3. 用当前 ChatGPT 登录态打开 OAuth URL。
4. 自动处理 `choose-an-account`、Codex consent、workspace select。
5. 拿到 `http://localhost:1455/auth/callback?code=...`。
6. 调用 Sub2API `exchange-code` 创建账号。
7. 保存 Sub2API 账号名、credentials、access token。
8. 写出 JSON。

异常分支：若 OAuth 触发 add-phone，工具改用 K12 Web AT 创建 noRT 账号。

#### 路径 B：Sub2API noRT 直入

条件：`runSub2Api=true` 且 `sub2apiNoRtMode=true`。

流程：

1. 强制执行 K12 workspace 加入。
2. 阶段 1：对所有 workspace 集中执行 request/accept。
3. 阶段 2：连续执行 session exchange，收集每个 workspace 的 AT。
4. 阶段 3：对每个 workspace AT 执行 Sub2API noRT upsert，并写 JSON。
5. 批量结束后只恢复一次个人/free workspace，减少反复切换导致旧 AT 失效。

#### 路径 C：JSON-only

条件：`runSub2Api=false` 且 `runWorkspaceJoin=true`。

流程：

1. 登录 ChatGPT Web 获取个人 AT。
2. 对每个 workspace 执行 request/accept。
3. 检查 membership。
4. session exchange 获取 workspace AT。
5. 批量结束后恢复个人/free workspace。
6. 只写 JSON，不写 Sub2API。

### K12 workspace 加入和切换

核心函数：

- `runK12WorkspaceInviteForWorkspace()`
- `runK12WorkspaceSwitchAndRecordForWorkspace()`
- `runK12WorkspaceJoinForWorkspace()`
- `runK12WorkspaceJoinAndExchangeForWorkspace()`

逻辑：

1. 先检查任务中是否已有成功记录。
2. 再检查邮箱缓存中 workspace 是否已经可见。
3. 未加入时调用 `sendK12Invite()`。
4. route 为 `request` 或 `accept`。
5. 加入后调用 accounts/check 验证 membership。
6. 切换 workspace 或 session exchange，拿到 workspace-scoped AT。
7. 校验 AT 是否属于目标 workspace。
8. 记录 AT，追加到 token 输出，写任务结果。

底层请求目标来自代码常量：

```text
https://chatgpt.com/backend-api/accounts/{workspace_id}/invites/{request|accept}
https://auth.openai.com/api/accounts/workspace/select
https://chatgpt.com/backend-api/accounts/check/v4-2023-04-27
```

### AT 测活与修复

测活入口：

- 任务级：`POST /api/tasks/check-at`
- 邮箱池/Sub2API 账号级：`POST /api/emails/check-at`

修复入口：

- `POST /api/tasks/repair-at`
- 执行器：`runAtRepairTask()`

修复逻辑：

1. 登录 Sub2API 管理端。
2. 按邮箱和分组推导账号名，查找 Sub2API 账号。
3. 若账号不存在，重新登录 ChatGPT 获取 K12 AT，新建 noRT 账号。
4. 若账号存在，先本地 test OpenAI AT。
5. 本地 AT 可用则只写 JSON，不更新 Sub2API。
6. 本地 AT 不可用，再测 Sub2API 账号。
7. 仍不可用则重新登录获取 K12 AT，更新 Sub2API 账号 credentials。
8. 若检测到 OpenAI 停用/封禁，邮箱标记 `banned`，停止修复。

### 自动补号

配置项：

- `sub2apiAutoRefillEnabled`
- `sub2apiRefillGroupName`
- `sub2apiRefillThreshold`
- `sub2apiRefillEmailCount`
- `sub2apiRefillIntervalMs`
- `sub2apiRefillDeepCheckEnabled`

逻辑：

1. 定时或手动读取 Sub2API 目标分组账号。
2. 统计正常账号数。
3. 可选深度测活。
4. 若正常数低于阈值，从空闲邮箱池创建新任务。
5. 写入补号历史。

## chatgpt-register-sub2api 工作逻辑

### CLI 命令

`cli.py` 暴露这些命令：

- `init`: 生成默认 `config.yaml`。
- `register`: 只注册 ChatGPT 账号。
- `join-workspace`: 对已有账号执行 K12 进组。
- `login-team`: 重新登录并选择 Team 空间。
- `export`: 导出 Sub2API JSON。
- `run`: 执行完整流水线。

### 配置

`config.example.yaml` 主要配置：

- `mail.providers`: Outlook token 邮箱池，格式为 `email----password----client_id----refresh_token`。
- `proxy.url`: HTTP/SOCKS 代理。
- `proxy.flaresolverr_url`: Cloudflare challenge 辅助。
- `registration.threads`: 注册线程数。
- `registration.total`: 注册数量。
- `workspace.ids`: K12 workspace UUID 列表。
- `workspace.route`: `request` 或 `accept`。
- `sub2api.output_file`: JSON 输出文件。

### run 完整流水线

`run_full_pipeline()` 实际执行：

```text
run_register()
  -> run_join_workspace()
  -> run_refresh_tokens()
  -> run_export()
```

注意：README 提到的 `re-login` 在源码中默认不启用。`run_re_login()` 只有 `workspace.re_login_enabled=true` 时才跑；完整 `run` 当前改为 refresh token 后调用 accounts/check 获取 `plan_type` 和 `chatgpt_account_id`。

### 注册阶段

`register/registrar.py` 中 `PlatformRegistrar.register()` 执行：

1. 从 Outlook token pool 获取邮箱。
2. 随机生成密码、姓名、生日。
3. 走 Platform OAuth authorize，生成 PKCE。
4. 调用 `auth.openai.com/api/accounts/user/register` 创建用户。
5. 调用 `email-otp/send` 发送验证码。
6. 轮询 Outlook Graph/IMAP 获取 6 位验证码。
7. 调用 `email-otp/validate` 校验验证码。
8. 调用 `create_account` 补全 profile。
9. 用 authorization code 交换 `access_token`、`refresh_token`、`id_token`。
10. 写入 `registered_accounts.json`。

注册会使用 `curl-cffi` 的 Chrome impersonation。遇到 Cloudflare challenge 时，若配置 FlareSolverr，会尝试刷新 clearance 后重试。

### 邮箱池

`register/mail_provider.py` 只保留 Outlook token pool：

- 解析 `email----password----client_id----refresh_token`。
- 状态文件：`data/outlook_token_state.json`。
- 状态：`in_use`、`used`、`token_invalid`、`failed`。
- `in_use` 超过 1 小时视为可释放。
- 验证码提取支持 OpenAI 邮件 HTML、英文/中文文本模式、通用 6 位码。

### workspace 加入

`workspace/joiner.py` 核心请求：

```text
POST https://chatgpt.com/backend-api/accounts/{workspace_id}/invites/{route}
Authorization: Bearer {access_token}
```

逻辑：

1. route 默认 `request`。
2. 多 workspace 顺序执行。
3. 401/403 直接判定 token 过期，需要重新登录。
4. 非鉴权错误按 `max_retries` 和 `retry_backoff_ms` 重试。
5. 每个 workspace 返回 `{ok, status_code, body, workspace_id}`。

### refresh/check 阶段

`run_refresh_tokens()` 对每个账号：

1. 用 `refresh_token` 请求 `https://auth.openai.com/oauth/token`。
2. 刷新 access token 和 refresh token。
3. 调用 `https://chatgpt.com/backend-api/accounts/check/v4-2023-04-27`。
4. 从返回中写入 `plan_type`、`chatgpt_account_id`、`account_user_role`。

`refreshed` 计数依据：`plan_type == "k12"`。

### 导出阶段

`export/sub2api.py` 构造 bundle：

```json
{
  "exported_at": "...",
  "proxies": [],
  "accounts": [
    {
      "name": "email@example.com",
      "platform": "openai",
      "type": "oauth",
      "credentials": {
        "access_token": "...",
        "refresh_token": "...",
        "id_token": "...",
        "chatgpt_account_id": "...",
        "chatgpt_user_id": "...",
        "client_id": "app_2SKx67EdpoN0G6j64rFvigXD",
        "email": "email@example.com",
        "expires_at": 1234567890,
        "organization_id": "",
        "plan_type": "k12",
        "session_token": ""
      },
      "extra": {
        "auth_provider": "chatgpt2api",
        "source": "registration",
        "privacy_mode": "training_off"
      },
      "concurrency": 10,
      "priority": 1,
      "rate_multiplier": 1,
      "auto_pause_on_expired": true
    }
  ]
}
```

若 `team_login_status == "ok"`，导出使用 `team_access_token`、`team_refresh_token`、`team_id_token`；否则使用注册/refresh 后 token。

## 两个工具差异

| 维度 | K12-Space-Automation | chatgpt-register-sub2api |
| --- | --- | --- |
| 形态 | Node/Vue 本地 Web 控制台 | Python CLI |
| 主用途 | 管理邮箱池、任务、K12、Sub2API、补号、修复 | 批量注册、进 K12、导出 Sub2API JSON |
| 注册能力 | 主要复用 `codex_register/`，也支持登录已有邮箱 | 内置 OpenAI 注册流程 |
| 邮箱来源 | 固定邮箱池、手动验证码、SMSBower Gmail、Emailnator | Outlook token pool |
| K12 模式 | request/accept，多 workspace，membership check，workspace token exchange | request/accept，多 workspace 顺序 POST |
| Sub2API | 支持在线 OAuth 入库、noRT upsert、多分组、补号 | 只导出 bundle JSON |
| 修复能力 | AT 测活、Sub2API 账号修复、封号标记 | 无修复闭环 |
| 运行数据 | `data/`, `json/`, token 输出 | `registered_accounts.json`, `data/outlook_token_state.json`, bundle JSON |

## 风险和注意点

- 真实邮箱、refresh token、Sub2API 密码、SMS API key、access token 都是敏感数据，不能提交到 Git。
- K12-Space-Automation README 明确说仓库默认不包含真实配置和运行数据；运行时文件应留在本地。
- 子模块 README 提到 K12 后端接口“无鉴权”现象，但实际使用仍依赖账号 Bearer token。此类流程可能受平台规则变化影响。
- OpenAI/Auth、ChatGPT accounts/check、workspace select、invites API 都不是稳定公开 API，字段和风控随时可能变。
- `chatgpt-register-sub2api` 的 `login-team` 默认不在完整 run 中执行，README 与当前源码有差异；文档和实际行为需以 `pipeline.py` 为准。

## 推荐阅读顺序

1. `packages/K12/README.md`: 看聚合说明和 K12 手工流程。
2. `packages/K12/K12-Space-Automation/README.md`: 看 Web 控制台能力。
3. `packages/K12/K12-Space-Automation/server/index.ts`: 看实际任务流。
4. `packages/K12/chatgpt-register-sub2api/README.md`: 看 CLI 用法。
5. `packages/K12/chatgpt-register-sub2api/chatgpt_register_sub2api/pipeline.py`: 看 CLI 实际完整流程。
