Files
Unlucky-Launcher/crates/core/src/auth/mod.rs
T
AskaEth 8194e38bcf feat(core): 加 MSA 授权码流(本地回调服务器)并接到账户页
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>
2026-11-01 08:33:11 +08:00

56 lines
2.8 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//! 账户体系:三轨(离线 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};