198 lines
11 KiB
Markdown
198 lines
11 KiB
Markdown
# ShaCraft Launcher architecture
|
|
|
|
## Current capability
|
|
|
|
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 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,
|
|
read-only `https://shacraft.ru/api/online/aoc` endpoint. It is display-only:
|
|
the result never controls files, versions, URLs, or the launch command.
|
|
|
|
Not yet implemented: a user-selectable profile directory, a "reset managed
|
|
files only" recovery action, and signed cross-platform release builds of the
|
|
launcher itself. Do not represent these as completed in UI or release notes.
|
|
|
|
## Data flow
|
|
|
|
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)
|
|
-> 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)
|
|
-> Java 21 via Adoptium if none installed (runtime.rs)
|
|
-> NeoForge's own installer, run headlessly (neoforge.rs)
|
|
-> generic inheritsFrom merge of the two version JSONs (mojang.rs)
|
|
-> SHA-1-verified merged libraries + platform natives (mojang.rs)
|
|
-> verified ShaCraft account link (shacraft_account.rs)
|
|
-> deterministic offline UUID for the linked nickname (session.rs)
|
|
-> java process spawned with the merged classpath/args (launch.rs)
|
|
```
|
|
|
|
Profiles (ShaCraft-managed mods/config, and the player's own worlds/
|
|
screenshots/resourcepacks) live below Tauri's `app_data_dir()/profiles/
|
|
<profile-id>` — this becomes `--gameDir`. The shared vanilla+NeoForge
|
|
install (versions/libraries/assets/runtime, reused across profiles that
|
|
target the same Minecraft version) lives at `app_data_dir()/game`. Settings
|
|
live at `app_data_dir()/settings.json`, and the revocable ShaCraft session at
|
|
`app_data_dir()/shacraft-session` (mode 600 on Unix). Passwords are never
|
|
written to disk. None of these should be assumed to
|
|
be the system `.minecraft` directory.
|
|
|
|
## Aeronautics contract
|
|
|
|
- Profile ID: `aeronautics`
|
|
- Manifest endpoint:
|
|
`https://shacraft.ru/api/launcher/v2/profiles/aeronautics/signed-manifest`
|
|
- Payload: manifest schema v1; also carries `minecraft.{version, loader,
|
|
javaMajor}` (currently 1.21.1, NeoForge 21.1.248, Java 21) — the launcher
|
|
reads this rather than hardcoding it, so a server-side version bump needs
|
|
no launcher release.
|
|
- ShaCraft download files: HTTPS only, exact hosts `shacraft.ru` and
|
|
`cdn.shacraft.ru`.
|
|
- Account API origin: fixed `https://shacraft.ru`; redirects are rejected.
|
|
- Launch identity: the most recently verified `aoc` nickname returned by the
|
|
authenticated account API. Local nickname edits cannot select an identity.
|
|
|
|
## Planned but not implemented
|
|
|
|
1. User-selectable profile directory and structured launcher logs.
|
|
2. "Reset managed files only" recovery action that doesn't touch player
|
|
worlds/screenshots/resourcepacks.
|
|
3. Signed, cross-platform release builds of the launcher itself.
|
|
4. Cancellation, structured logs and a full cold-install/recovery beta on
|
|
every target OS. Install progress reports bytes or installer work counts
|
|
depending on the stage; these units are not interchangeable.
|
|
|
|
Do not represent these as completed features in UI or release notes.
|
|
|
|
|
|
## Module boundaries (2026-09-09)
|
|
|
|
React entrypoint → App/components → hooks → typed native service. Pure
|
|
reducers own game and profile states; IPC failures retain their real message.
|
|
Settings writes are serialized, and account restoration is single-flight
|
|
even under React StrictMode. A failed repair invalidates profile readiness.
|
|
Game exit may arrive before launch acknowledgement; the reducer handles both.
|
|
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.
|
|
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
|
|
URLs and redirects. Manifest profile identity, size, signature, portable
|
|
paths and existing symlinks are checked before managed file writes.
|
|
Hostile same-user TOCTOU is outside this protection; it is not an OS sandbox.
|
|
|
|
## Verification and distribution
|
|
|
|
`npm test` covers asynchronous helpers and state transitions;
|
|
`npm run build` runs strict TypeScript before Vite. `cargo test --locked`
|
|
covers native policy and storage. Push/PR CI repeats checks on Linux.
|
|
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/.<profile-id>.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/<version>.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 <id> <code>`.
|
|
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.
|