feat: add Codex auth login and export flow

Add Codex Auth support in account management so selected accounts can
complete a Codex-compatible OAuth login flow and export usable auth.json
files.

This commit includes:
- account-management UI entrypoints for Codex Auth login and auth.json download
- backend SSE routes for single-account and batch Codex Auth login execution
- persistence of freshly returned Codex-compatible tokens back into the account database
- Codex auth export support for direct auth.json download and batch zip packaging
- tests covering the Codex Auth login flow and export behavior

The OTP verification failure was caused by manually sending a second OTP after
password verification. The flow now reuses the existing proven login path:
login re-entry, password verification, automatic OTP reception, consent page
handling, workspace selection, and OAuth callback exchange.

Successful logins now also persist workspace_id together with the refreshed
Codex-compatible tokens, making later re-export of auth.json possible without
requiring the browser-downloaded file to still exist locally.

Change-Id: I59df518ef4dc05f8bc52c734dd1b738fcb0b7a4e
This commit is contained in:
Solo
2026-03-25 16:31:03 +08:00
parent 1cbb95f91c
commit f4d0327f67
11 changed files with 1266 additions and 13 deletions

View File

@@ -139,7 +139,10 @@
</div>
</div>
<button class="btn btn-danger" id="batch-delete-btn" disabled>
🗑️ 批量删除
删除
</button>
<button class="btn btn-primary" id="codex-auth-login-btn" disabled>
Codex Auth
</button>
<div class="dropdown">
<button class="btn btn-primary" id="export-btn">
@@ -150,6 +153,7 @@
<a href="#" class="dropdown-item" data-format="csv">导出 CSV</a>
<a href="#" class="dropdown-item" data-format="cpa">导出 CPA 格式</a>
<a href="#" class="dropdown-item" data-format="sub2api">导出 Sub2Api 格式</a>
<a href="#" class="dropdown-item" data-format="codex_auth">导出 Codex Auth 格式</a>
</div>
</div>
</div>
@@ -277,6 +281,24 @@
</div>
</div>
<!-- Codex Auth 登录进度弹窗 -->
<div class="modal" id="codex-auth-modal">
<div class="modal-content" style="max-width: 600px;">
<div class="modal-header">
<h3>Codex Auth 登录</h3>
<button class="modal-close" id="close-codex-auth-modal">&times;</button>
</div>
<div class="modal-body">
<div id="codex-auth-status" style="margin-bottom: 12px; font-weight: 600;"></div>
<div id="codex-auth-logs" style="max-height: 300px; overflow-y: auto; background: var(--bg-secondary); border-radius: 6px; padding: 10px; font-size: 0.85rem; font-family: monospace; white-space: pre-wrap; line-height: 1.5;"></div>
</div>
<div class="modal-footer" style="padding: 12px 20px; border-top: 1px solid var(--border); display: flex; gap: 8px; justify-content: flex-end;">
<button class="btn btn-primary" id="codex-auth-download-btn" style="display: none;">下载 auth.json</button>
<button class="btn btn-secondary" id="close-codex-auth-modal-btn">关闭</button>
</div>
</div>
</div>
<script src="/static/js/utils.js?v={{ static_version }}"></script>
<script src="/static/js/accounts.js?v={{ static_version }}"></script>
</body>