Harden OOBE, launch-source and elevation flow

Introduce a per-user OOBE state model and hardened launch/elevation handling. Adds OobeStateFile/OobeLaunchDecision models, OobeStateService (persisting %LOCALAPPDATA%/.launcher/state/oobe-state.json), and LauncherExecutionContext to capture elevation and user SID. CommandContext now normalizes/infers launch-source values (normal, postinstall, apply-update, plugin-install, debug-preview) and exposes maintenance checks. LauncherFlowCoordinator propagates richer launcher context details for diagnostics and suppresses OOBE for elevated/maintenance contexts. PluginInstallerService avoids requesting elevation for user-scoped installs and returns a clear error when installation target is outside the current user's LocalAppData. LauncherClient maps and surfaces result codes, UpdateWorkflow and installer invocation now pass explicit --launch-source values, and WelcomeOobeStep persists OOBE completion via the new service. Adds unit tests (CommandContext, OobeStateService, PluginInstallerService), docs/specs/checklists for the contract, and makes internals visible to tests.
This commit is contained in:
lincube
2026-04-22 09:25:22 +08:00
parent 703ed7b48a
commit 9224c9a33a
28 changed files with 843 additions and 109 deletions

View File

@@ -200,3 +200,15 @@ The runtime flow starts with the Launcher selecting the best version, then proce
- Incremental package build/publish has moved to VeloPack native assets (
eleases.win.json + *.nupkg).
- Launcher runtime responsibilities are unchanged: OOBE, startup orchestration, update apply, and rollback.
## Launcher OOBE / Elevation Contract
- Launcher OOBE state is owned by a per-user JSON file under `%LOCALAPPDATA%\LanMountainDesktop\.launcher\state\oobe-state.json`.
- Same-user reinstall or upgrade should keep OOBE completed.
- `first_run_completed` is legacy migration-only data.
- The recognized launch sources are `normal`, `postinstall`, `apply-update`, `plugin-install`, and `debug-preview`.
- Auto-OOBE is only allowed for normal user-mode startup.
- `postinstall` may show OOBE only when the launcher is not elevated.
- `apply-update`, `plugin-install`, and `debug-preview` must not auto-open OOBE.
- Elevation is allowed only for the installer, full installer update application, and user-confirmed legacy uninstall.

View File

@@ -547,3 +547,15 @@ var updateCheckService = new UpdateCheckService(
- [构建和部署指南](BUILD_AND_DEPLOY.md)
- [架构文档](ARCHITECTURE.md)
- [开发文档](DEVELOPMENT.md)
## Current OOBE and Elevation Contract
- OOBE state is a per-user truth source stored at `%LOCALAPPDATA%\LanMountainDesktop\.launcher\state\oobe-state.json`.
- Same-user reinstall or upgrade must not re-enter OOBE.
- `first_run_completed` is legacy compatibility data only and should not remain the long-term primary format.
- Launch source values are `normal`, `postinstall`, `apply-update`, `plugin-install`, and `debug-preview`.
- Auto-OOBE is allowed only for normal user-mode startup.
- `postinstall` may open OOBE only when the launcher is not elevated and the user state path is available.
- `apply-update`, `plugin-install`, and `debug-preview` must not auto-enter OOBE.
- Allowed elevation paths are limited to the installer itself, full installer update application, and user-confirmed legacy uninstall.
- Default plugin installation targets the current user's LocalAppData scope and must not request elevation by default.

View File

@@ -642,3 +642,40 @@ xattr -cr /Applications/LanMountainDesktop.app
- [Launcher 鏋舵瀯](LAUNCHER.md)
- [鏇存柊绯荤粺](UPDATE_SYSTEM.md)
- [鏋勫缓鍜岄儴缃瞉(BUILD_AND_DEPLOY.md)
### 问题: OOBE 窗口重复出现
**原因:** OOBE 完成标记丢失、损坏,或者旧版标记文件只作为迁移兼容而不是主状态源。
**当前权威状态路径:**
```bash
Windows: %LOCALAPPDATA%\LanMountainDesktop\.launcher\state\oobe-state.json
```
**处理原则:**
- 同一 Windows 用户重装或升级后,默认不应该再次进入 OOBE。
- `first_run_completed` 只保留为兼容迁移数据。
- 如果状态文件不可读Launcher 应优先保证稳定启动并记录 `oobe_state_unavailable`,不要反复把用户拉回 OOBE。
---
### 问题: 启动或插件安装意外弹出管理员权限
**原因:** 某些路径显式请求了 `runas`,或者流程把默认用户目录误判成需要提权。
**当前允许提权的白名单:**
- 安装器本体
- 全量安装包更新应用
- 用户显式确认的 legacy uninstall
**不应弹 UAC 的场景:**
- 普通冷启动
- OOBE
- 检查更新
- 增量下载
- 默认插件安装到用户 LocalAppData 路径
**调试建议:**
- 检查日志中的 `launchSource``isElevated``oobeStateStatus``oobeSuppressionReason`
- 检查插件安装目标是否仍在 `%LOCALAPPDATA%\LanMountainDesktop`
- 确认没有额外的 `Verb = "runas"` 被引入默认路径