research/08 方案 A:GUI 的微软登录改走授权码流(HMCL 主流做法),设备码流保留给 CLI/无浏览器场景。两条流只差「怎么拿到 MS access_token」,拿到之后共用 chain::complete_chain 与 MicrosoftSession,落盘/刷新语义没有第二套。 core(crates/core/src/auth/microsoft/) - endpoints:新增 authorize(…/consumers/oauth2/v2.0/authorize),与 token 同租户。 - authcode:RedirectUri 是 http://localhost:{port}/auth 的唯一来源(授权 URL、 token 请求体、实际监听三处共用,坑 5);AuthCodePolicy(回调超时 300s / 绑定重试 3 次 / 固定端口 / 固定 state);authorization_url(response_type=code + prompt=select_account + scope=XboxLive.signin%20offline_access);exchange_code 复用 flow 的 oauth_error/tokens_from。 - callback:本地 HTTP/1.1 回调服务器。内核分配端口(占用按次数退避重试);非 /auth 路径 (favicon、预连)404 后继续等;state 不匹配 400 后继续等;error=access_denied 归 Canceled; 单条连接读头超时 5s,半开连接拖不垮时间预算。 - MicrosoftAuth::authcode_login(present):绑端口 → present(宿主开浏览器)→ 等回调 → 换 token → 整链;失败与设备码流一样落 M38 失败日志。 app(crates/app) - AppCommand::StartBrowserLogin + host::accounts::start_browser_login;设备码/授权码共用 LoginJob 取消槽位、收尾入库(store_session)与面板 DTO。 - host::opener 用系统默认浏览器打开授权 URL(Windows rundll32 url.dll,FileProtocolHandler)。 - 账户页:主按钮「微软登录」走授权码流,「设备码登录」作备用;DeviceLoginView::browser_waiting 在面板里给出可复制的授权链接(user_code 留空)。 测试 - crates/core/tests/auth/microsoft_authcode.rs:授权 URL 向量(租户/编码/prompt)、 URI 一致性(授权 URL 与 token 表单同字面量)、mock 全链、favicon+陈旧 state 后仍拿到 code、 端口占用重试文案、超时、access_denied→Canceled、login_with_xbox 403 的 M38 诊断 (detail_code=login_with_xbox_403,真机白名单未批时验收止步于此)。 - 单测:authcode 编码/向量、callback query 解码与错误分流、DTO browser_waiting、conv 面板。 未做/未验证:真机完整登录需 Azure 公共客户端 id(ULL_MSA_CLIENT_ID)与 Minecraft API 许可, 本机只能到「授权页 302 到 login.live.com 且 redirect_uri/scope/prompt 原样保留」这一步。 AskaEth <i@yeij.top>
56 lines
2.8 KiB
Rust
56 lines
2.8 KiB
Rust
//! 账户体系:三轨(离线 UUID / 微软 device-code 与授权码 / authlib-injector)、凭据存储边界。
|
||
//!
|
||
//! 设计定稿:`DevDocs/PlanDoc/07-accounts.md`(决策 D9/Q21),协议细节来自
|
||
//! `DevDocs/analyse/04-authentication.md`(HMCL v3.17 拆解,逐报文对照)。
|
||
//!
|
||
//! # 三条铁律
|
||
//!
|
||
//! 1. **凭据永不外泄**:token/密码不落日志、不进事件流、不打印(`AGENTS.md` §6、D4)。
|
||
//! 类型层保证:[`Secret`] 的 `Debug`/`Display` 恒为 `<redacted>`,取明文只能 `.expose()`;
|
||
//! 对外展示一律走元数据([`AccountMeta`],不含凭据)。
|
||
//! 2. **账户操作永不 YOLO**:本模块不向 AI 暴露任何账户读写面(07 §3);
|
||
//! CLI 也只开 `list / add offline / add msa / remove` 四条(authlib 密码登录走 GUI 输入框,
|
||
//! 避免密码进 argv)。
|
||
//! 3. **元数据 / 凭据分文件**:`data/auth/accounts.json` + `data/auth/credentials.dat`,
|
||
//! 先写凭据后写元数据,原子写,单条坏记录只跳过不整体失败。
|
||
//!
|
||
//! # 公共面
|
||
//!
|
||
//! - [`account`]:`AccountId` / `AccountKind` / `AccountMeta` / `Credentials`(三轨统一抽象);
|
||
//! - [`store`]:`AccountStore`(加载/增删/落盘,`data/auth/`);
|
||
//! - [`offline`]:HMCL 兼容离线 UUID + 启动占位;
|
||
//! - [`microsoft`]:微软两条登录流(device-code / 授权码+本地回调)+ 共用后链
|
||
//! (XBL→XSTS→login_with_xbox→entitlements→profile)+ 刷新判定;
|
||
//! - [`authlib`]:标准 Yggdrasil 协议(authenticate/refresh/validate/invalidate,账户侧);
|
||
//! - [`error`]:错误分流(取消 / 超时 / 被拒 / 凭据过期);
|
||
//! - [`body`]:非 2xx 应答的正文诊断(分类 JSON/HTML/空体 + 脱敏摘要,M38);
|
||
//! - [`journal`]:认证失败事件落盘(`.ULL/logs/auth.jsonl`,M38);
|
||
//! - [`secret`]:凭据值包装与脱敏。
|
||
//!
|
||
//! # 本期不做(后续 mission)
|
||
//!
|
||
//! OS keychain / AES-256-GCM 凭据加密(07 §2 分级 1–2)、authlib-injector 的
|
||
//! `-javaagent` 三件套与 jar 下载、皮肤与多角色选择、离线 UUID 的「官方风格」双模式
|
||
//! (07 §1 升级 2,口径待定案)。接口约定见 `DevDocs/SubAgentsTalk/auth-接口约定.md`。
|
||
|
||
pub mod account;
|
||
pub mod authlib;
|
||
pub mod body;
|
||
pub mod error;
|
||
pub mod http;
|
||
pub mod journal;
|
||
pub mod microsoft;
|
||
pub mod offline;
|
||
pub mod secret;
|
||
pub mod store;
|
||
|
||
pub use account::{AccountId, AccountKind, AccountMeta, Credentials};
|
||
pub use body::{BodyKind, ResponseDetail};
|
||
pub use error::{AuthError, AuthResult};
|
||
pub use journal::{AuthFailureEvent, AuthJournal};
|
||
pub use microsoft::{
|
||
AuthCodePolicy, AuthCodePrompt, MicrosoftAuth, MicrosoftSession, RefreshDecision, RefreshReason,
|
||
};
|
||
pub use secret::Secret;
|
||
pub use store::{AccountStore, AuthPaths};
|