diff --git a/AGENTS.md b/AGENTS.md index 68ff036..c20040c 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -30,8 +30,12 @@ payload are in `/root/shacraft` on the ShaCraft host; see embedded public key and `keyId` **before** parsing the payload. - `src-tauri/src/manifest.rs` then validates paths, SHA-256, sizes, HTTPS and allowed ShaCraft hosts. Do not weaken this whitelist. -- `src-tauri/src/profile.rs` downloads to a temporary sibling file, verifies - size + SHA-256, and atomically replaces only launcher-managed files. +- `profile.rs` / `inventory.rs` stage verified files, journal replacements and + retire only previously owned, unchanged managed files. Unknown files are not + silently adopted or deleted. Legacy mod backup requires explicit selection. +- Play/Repair use one `remote::VerifiedSnapshot` from verification through spawn. + `installation_lock.rs` protects the shared game tree across processes and + retains a PID + start-time lease while Minecraft is alive. - This ShaCraft manifest is the **only** source of truth for which Minecraft version / NeoForge version / Java major a profile needs (`Manifest.minecraft`) and for mod/config files. It never supplies a URL @@ -45,7 +49,12 @@ payload are in `/root/shacraft` on the ShaCraft host; see the nickname is fetched from the verified `aoc` account link; the legacy nickname in `settings.json` is ignored as an identity source. Server-side whitelist enforcement and LoginSystem remain the final access-control - boundary, including for old launcher versions. + boundary, including for old launcher versions. The explicit onboarding command + is the only unlinked launch path: a short-lived server grant goes to the game + child environment only, never IPC responses, argv or files. The signed pack + must contain ShaCraft Game Bridge; it binds the grant to the game session, + requires LoginSystem authentication and an explicit one-time proof command. + Existing links retain legacy provenance; status polling cannot create links. ## Layout @@ -69,7 +78,9 @@ payload are in `/root/shacraft` on the ShaCraft host; see build on this rather than each rolling their own. - `mojang.rs` — vanilla Minecraft trust boundary + the generic `inheritsFrom` version-JSON merge (shared with NeoForge's profile). - - `neoforge.rs` — runs NeoForge's official installer headlessly. + - `neoforge.rs` / `neoforge_repair.rs` — verified official installer, isolated + processor rebuild, checked embedded JSON and generated-output receipts. + Never hash legacy generated artifacts as an initial trusted baseline. - `runtime.rs` — Java 21 auto-provisioning via Eclipse Adoptium. - `msa.rs` — Microsoft/Xbox/Minecraft Services login; see `MSA_CLIENT_ID`'s doc comment before touching login — it is currently a diff --git a/PLAN.md b/PLAN.md index 27775b2..dd23a02 100644 --- a/PLAN.md +++ b/PLAN.md @@ -20,13 +20,23 @@ - [ ] Подписанные installer-релизы и подписанное автообновление лаунчера. - [ ] Реальная отмена загрузок, журнал с редактированием токенов и retry UX. - [ ] Выбор каталога профиля и безопасный reset только managed-файлов. -- [ ] Keychain-хранилище refresh token; cross-process exclusion при необходимости. +- [ ] Keychain-хранилище сессии ShaCraft; OS-lock и lease игры уже реализованы. - [ ] Динамический каталог и новости; реальный Aeronautics онлайн уже загружается через фиксированный display-only API. Не имитировать данные. -## Связанные серверные риски +## Исправления по handoff (исходники, до выкладки) -Серверный план находится в `/root/shacraft/PLAN.md`. Важные следующие шаги: -одноразовое подтверждение ника внутри игры (NoGravity не связывает игрока -с веб-запросом), enforcement реферальных правил и очередь повторов whitelist. -Не менять этот протокол незаметно в клиентском рефакторинге. +- [x] Один signed snapshot и общий межпроцессный lock на Play/Repair. +- [x] Inventory, journal/recovery, retirement старых неизменённых managed-файлов. +- [x] Явный перенос выбранных legacy-модов в резервную копию. +- [x] NeoForge clean rebuild + provenance receipt; непустая порча обнаруживается. +- [x] Отдельный первый вход с серверным grant и одноразовым proof. +- [x] RAM retry сохраняет намерение; неверный JAVA_HOME не скрывает подходящий PATH. +- [x] Версии в интерфейсе берутся из проверенного manifest. +- [ ] Совместная выкладка backend/Game Bridge/подписанного payload и нового лаунчера. +- [ ] Изолированная игровая проверка LoginSystem + hold + proof, затем beta по ОС. + +Сопутствующий серверный код содержит read-only status, nonce proof с legacy +migration и durable grant/revoke outbox. Оплата и доставка whitelist — разные +состояния. Реферальные правила остаются отдельной задачей серверного PLAN; +это исправление не меняет условия покупки. Продакшен не изменён. diff --git a/README.md b/README.md index ac41dd6..f7da5ed 100644 --- a/README.md +++ b/README.md @@ -5,11 +5,17 @@ React/TypeScript интерфейс, Rust — файлы, сеть и запус Реализованы подписанная синхронизация Aeronautics, проверка/восстановление модов и конфигурации, Java discovery/provisioning, bootstrap Minecraft и -NeoForge, настройки памяти и ника, обработка установки/запуска/выхода. +NeoForge, настройки памяти, обработка установки/запуска/выхода. Проверка +сборки теперь восстанавливает и игровые файлы; старые неизменённые managed-моды +убираются в резервную копию, неизвестные моды разбираются явно пользователем. Вход выполняется через аккаунт ShaCraft — тот же, что на сайте. Игровой ник берётся только из подтверждённой привязки Aeronautics, а не из редактируемых локальных настроек. Пароли не сохраняются; сессию можно отозвать. +Для первого входа без привязки добавлено отдельное действие в настройках +аккаунта: установка → серверное разрешение → LoginSystem → одноразовая команда +подтверждения. Оно требует совместной выкладки backend, Game Bridge и +подписанного модпака; наличие исходников не означает публикацию этого сценария. Microsoft OAuth-модуль сохранён отдельно, но не используется текущим сценарием запуска; для его активации потребуются client ID и API approval. diff --git a/docs/game-trust-boundary.md b/docs/game-trust-boundary.md index 2fe8882..e62eb96 100644 --- a/docs/game-trust-boundary.md +++ b/docs/game-trust-boundary.md @@ -90,3 +90,25 @@ URL — cannot redirect a download to an attacker-controlled host in any of these domains. When adding a new game-related download, verify its host is one of the ones above (or add a new hardcoded constant following the same pattern) rather than accepting a URL from anywhere else. + + +## Generated NeoForge artifacts and Java selection + +NeoForge 21.1.248's actual installer does not publish processor-output hashes. +The launcher therefore validates the installer SHA-256, extracts its expected +version JSON and a scoped processor recipe, verifies the vanilla input against +Mojang, and runs that installer in a fresh staging tree. Generated JARs must +be readable ZIPs with valid entries. A receipt commits the generated hashes, +installer digest and recipe identity only after successful verified promotion. +This is provenance from a trusted computation, not independent publisher +checksums for generated files. Later corruption invalidates the receipt and +triggers clean reconstruction; a nonempty old file is never enough. Interrupted +promotion has no valid receipt and is repaired on the next preparation. +Only recipe-scoped generated artifacts are promoted; user profile files are +outside this tree. Staging can remain after an abrupt kill and is never trusted +as an installation. The receipt currently lives under the shared game cache. + +Java discovery evaluates JAVA_HOME and PATH candidates independently for the +exact required major. A wrong-major JAVA_HOME no longer hides a valid PATH +installation. Only if no matching candidate exists is a managed runtime +provisioned. The UI reads required versions from verified profile metadata. diff --git a/docs/launcher-architecture.md b/docs/launcher-architecture.md index 2c56b92..881358b 100644 --- a/docs/launcher-architecture.md +++ b/docs/launcher-architecture.md @@ -6,7 +6,7 @@ The launcher persists local settings, synchronises Aeronautics mod/config files from the signed ShaCraft v2 manifest, installs the exact Minecraft + NeoForge version the manifest specifies, and launches the game. A player signs in with the same local ShaCraft account used on the website. The game -identity is derived only from that account's verified Aeronautics nickname; +identity for ordinary Play is derived only from that account's verified Aeronautics nickname; the legacy editable nickname setting is not trusted at launch. The interface also shows a live Aeronautics player count from the fixed, @@ -19,13 +19,16 @@ launcher itself. Do not represent these as completed in UI or release notes. ## Data flow -Two independent pipelines feed one launch: +One verified ShaCraft snapshot is fetched inside the installation lock for +each Play/Repair operation. Every stage, the displayed completion metadata and +the spawn use that snapshot; a newly published manifest is used next time. +Two independent trust pipelines feed one launch: ```text ShaCraft manifest (mods/config + which MC/loader/Java version to use) signed-manifest endpoint -> Ed25519 verification (remote.rs) -> manifest schema + URL/path validation (manifest.rs) - -> temporary download, SHA-256 verification, atomic replacement (profile.rs) + -> inventory reconciliation, verified staging, durable apply journal (profile.rs) Game itself (never controlled by the manifest above) Mojang version manifest -> SHA-1-verified version JSON (mojang.rs) @@ -88,7 +91,10 @@ Browser preview cannot install/launch and does not simulate download progress. Rust `lib.rs` registers commands from `commands/`. Installation and account permits in `operations.rs` stay owned by blocking workers until completion. ShaCraft sessions have a separate gate from the retained Microsoft module. -These are process-local guards, not cross-process locks or cancellation. +An additional OS file lock in `installation_lock.rs` covers all profiles and +the shared game installation across processes. It remains held by the child +watcher; a durable PID/start-time lease also protects a game that outlives its +launcher. This is exclusion, not cancellation. `storage.rs` provides unique temporary files and atomic replacement; Unix session files are created owner-only. Windows keeps a recoverable replacement fallback if the OS refuses direct replacement. `trusted_http.rs` constrains provider @@ -105,3 +111,87 @@ The package workflow runs on main pushes or manually and builds Windows x64, Linux x64 and both macOS architectures with named artifacts. Packages are not yet signed release artifacts. Native cold-install and launch tests are required before calling a platform release-ready. + + +## Reconciliation and recovery + +`profiles/..shacraft-state/` is outside the payload root. It stores +`inventory.json`, `pending.json`, transaction staging/backups/receipts and +explicit legacy-mod backups. The inventory records only files the launcher +actually wrote, with size/hash/policy and signed snapshot digest. An existing +file that already matches is usable, but is not silently claimed as owned. +Seed files are never owned for later removal. + +All required downloads are staged and verified before apply. A write-ahead +journal records old/new states. Interrupted apply resumes by checking hashes; +readiness stays false while a journal, stale owned files or conflicts remain. +Old owned files are moved to a backup only when their current contents still +match the recorded version. Changed files remain conflicts; unrelated files +and player worlds, screenshots, options and resourcepacks are preserved. +A manifest is not authority to overwrite an unknown colliding local file. + +“Разобрать моды” lists legacy/changed JAR candidates without selecting any. +The user explicitly chooses paths; native code rechecks each selected hash +and safe path before moving it to a recoverable backup with a receipt. Unknown +extra mods are informational, not automatically removed or adopted. Readiness +means the declared pack files were checked; it does not certify arbitrary +additional user mods. Afterwards rerun Repair or Play. + +`game/cache/neoforge-receipts/.json` records provenance for generated +NeoForge outputs. The verified installer recipe and its embedded version JSON +scope which files can be rebuilt. Missing/invalid receipts, corrupt JSON or a +mismatched generated JAR cause a clean isolated rebuild. No local legacy hash +is accepted as the first baseline. See `game-trust-boundary.md`. + +## First entry and account proof v1 + +The account settings offer “Установить и войти для подтверждения” separately +from ordinary Play. The launcher prepares the exact signed pack first, then +requests and validates an authenticated grant at the fixed ShaCraft origin: +`POST /api/launcher/onboarding/start` and `/validate`. It requires an approved +managed `mods/shacraft-game-bridge-*.jar` entry in that signed snapshot. Until +that payload and server bridge are deployed, this action fails with an explicit +message; ordinary linked Play keeps its existing account gate. + +The grant binds account, `aoc`, exact nickname/offline UUID, challenge and TTL +(10 minutes). Only the game child gets `SHACRAFT_ONBOARDING_TOKEN` in its +environment; normal launches remove inherited tokens. The frontend receives +only the explicit proof challenge. The client bridge sends the token once to +the fixed Aeronautics socket. The server bridge holds that connection until +LoginSystem succeeds and the player enters `/shacraft link `. +The bridge uses a server-only bearer secret for fixed HTTPS callbacks. A grant +is not a whitelist grant, password replacement or completed web link. + +New nicknames keep the established operator-whitelist → first `/register` +policy; registered names must use their existing `/login` password. Prism can +still perform the explicit proof command without a launcher grant. Existing +account links stay valid with legacy provenance and optional re-verification; +no bulk revocation occurs. GET link status is read-only. Backend implementation, +migrations, game adapter and rollout procedure are in the companion server +repository, `docs/account-proof-v1.md` and `docs/access-delivery.md`. + +## Interrupted spawn recovery + +`installation-state/writer.lock` is an OS lock file, not a stale-lock sentinel; +never delete it while any launcher/game is running. `game-lease.json` records +`Starting` before spawn and `Running` with PID/start time before releasing the +worker. A known exited child is cleared automatically. A crash in the narrow +spawn/record interval or malformed lease fails closed because the child cannot +be proven absent. + +For that explicit error only: close all ShaCraft Launcher and Minecraft +processes (or reboot), verify none remain, and rename `game-lease.json` to a +backup outside `installation-state`. Then open one launcher and run Repair. +Do not remove game/profile trees or an active lock file as a recovery shortcut. +The application data root is shown in settings; it is not system `.minecraft`. + +## Local live preparation check + +`cargo test --locked --manifest-path src-tauri/Cargo.toml +commands::game::tests::live_cold_install_and_corruption_repair -- --ignored --nocapture` +uses a fresh temporary application directory, real signed/provider downloads +and the official installer. It corrupts generated NeoForge JSON/JAR, repairs +both and repeats a healthy check. It never logs into a game server. It requires +network access and sufficient disk space; the printed directory is retained +for diagnosis. This does not replace Tauri IPC, graphical gameplay or the +client/server proof matrix on each supported OS.