Files
shacraft-launcher/AGENTS.md
T

17 KiB

ShaCraft Launcher — agent context

Purpose and scope

Cross-platform desktop launcher for the ShaCraft Minecraft network. It is a Tauri 2 application: React/Vite is the UI and Rust owns all filesystem, network and process-adjacent work. Profiles are Aeronautics (Minecraft 1.21.1, NeoForge 21.1.248, Java 21) and Minigames (Minecraft 26.2, Fabric 0.19.5, Java 25). See the Minigames integration record below and docs/release-0.1.6.md for publication evidence.

This repository owns the launcher only. The server-side API and published payload are in /root/shacraft on the ShaCraft host; see docs/launcher-architecture.md before changing an integration boundary.

Non-negotiable boundaries

  • Launcher-managed payload is limited to ShaCraft-owned configuration and approved modpack files. Never make arbitrary URLs, shell commands, or local paths controllable by a remote manifest.
  • Do not add private keys, OAuth secrets, .env values, player data, or built artifacts to Git.

Trust model

  • The only supported remote profile manifest endpoints are the fixed https://shacraft.ru/api/launcher/v2/profiles/aeronautics/signed-manifest and https://shacraft.ru/api/launcher/v2/profiles/minigames/signed-manifest. The read-only Aeronautics player-count endpoint https://shacraft.ru/api/online/aoc is also hardcoded in remote.rs; it is display-only and is never allowed to influence downloads or launching.
  • The response is an Ed25519 envelope. src-tauri/src/remote.rs verifies its 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.
  • 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 for the game itself — see docs/game-trust-boundary.md for the four independent, hardcoded-host trust domains (Mojang, NeoForge, Microsoft, Adoptium) that install and run the actual game. Do not let manifest data control a URL in any of those domains.
  • ShaCraft accounts: src-tauri/src/shacraft_account.rs talks only to the hardcoded https://shacraft.ru origin. Passwords are never persisted. The revocable session token is stored locally with mode 600 on Unix and never passed to Java. The new admission flow uses fixed POST endpoints /api/launcher/v2/admission/nickname and /api/launcher/v2/admission/tickets; redirects are rejected. Neither the manifest nor the webview can select their origin or URL.
  • Free nicknames are claimed directly for the authenticated account. Existing player names are reserved server-side and assigned by an administrator; deleting a website account must not make an existing player's name free.
  • After installation, admission.rs generates an ephemeral Ed25519 key with the OS CSPRNG. The backend binds its public key to a one-use ticket, current account session, canonical aoc nickname and server access. Only that returned nickname selects launch identity; settings.json is never a fallback. Ticket and PKCS#8 private key go only in the final Java child's environment (SHACRAFT_ADMISSION_TICKET, SHACRAFT_ADMISSION_PRIVATE_KEY). Never put them in global environment, argv/argfiles, settings, logs or IPC. A fresh launch obtains a fresh ticket; there is no shared launcher secret.
  • Once admission is enforced on Aeronautics, its server mod verifies the challenge/proof before world entry, and server-side whitelist enforcement remains a final access boundary. Replace LoginSystem only as part of the validated aoc rollout; other servers are unaffected. Old launchers without admission proof will be rejected after enforcement. This authenticates an account's permission, not the integrity of an unmodified launcher binary.
  • Application updates are a separate trust domain from Minecraft profiles. The only channel is https://shacraft.ru/launcher/updates/stable.json. Both release metadata and the installer need a valid Minisign signature under the separate updater public key embedded in tauri.conf.json. Never reuse the profile signing key, accept unsigned metadata, or allow IPC to select an update URL, key, version, installer argument or destination. Downloads require HTTPS without redirects on exact shacraft.ru, below /downloads/shacraft-launcher/<signed-version>/, and are bounded to 256 MiB. Stable versions must increase. The native layer owns every candidate.
  • Linux self-update supports AppImage and an installed sha-craft-launcher deb. AppImage preserves executable permissions and uses same-directory atomic replacement after verification. Deb selects only the signed linux-x86_64-deb entry; retain legacy linux-x86_64 AppImage metadata for installed 0.1.3 clients. Never silently switch installation formats.
  • Deb elevation uses only /usr/bin/pkexec --disable-internal-agent and the root-owned installed /usr/bin/shacraft-launcher --shacraft-install-deb. This early helper mode never starts GTK/Tauri or account/network code. It receives bounded metadata/package bytes over stdin, not paths or commands, and re-verifies both signatures with the embedded key as root. Before the fixed dpkg installation, require exact package name, architecture and signed version, root-only staging and monotonic installed-package version; pass --refuse-downgrade to dpkg to close concurrent-update races. No system password collection, sudo fallback or permissive polkit policy is allowed. Cancellation, denied authorization and a busy package manager stay distinct. Windows/macOS use the pinned Tauri installer implementation; the vendored updater change only exposes construction from already verified metadata to avoid a second, unbounded remote JSON request. See its patch notes. Installation holds game/install/account permits until restart. The game permit lasts until the tracked Java child exits. These are process-local guards; another launcher process is not a cross-process lock.
  • The updater signing private key stays outside Git on the operator's local machine; CI receives no production key. Publish only verified packages, public signatures and signed feed. Updater signatures are separate from Windows Authenticode and macOS code signing/notarization.

Layout

  • src/main.tsx — React entrypoint; src/App.tsx composes the screen.
  • src/components/ — presentational UI; src/hooks/ — lifecycle/settings/account.
  • src/services/native.ts — typed IPC and event subscriptions; keep schemas aligned with Rust. src/services/async.ts — serialized writes, single-flight account restore and listener disposal. src/state/ — tested reducers.
  • Native filesystem/network/process operations never belong in the web layer.
  • src-tauri/src/ — native commands and security-sensitive logic.
    • lib.rs — module/command registration only; commands/ holds adapters for account/game/host/preferences/profiles. Unsigned sync/inspect IPC was removed; only verified remote manifests may drive profile mutations.
    • operations.rs — process-local install/account permits owned by workers. The account permit covers ticket issuance through Java spawn, preventing local logout/account switching from racing that handoff.
    • storage.rs — unique same-directory atomic writes, owner-only Unix files.
    • trusted_http.rs — HTTPS and exact-host redirect policy per game provider.
    • download.rs — shared verified-download helper (temp file, hash, atomic rename, progress callback); manifest.rs/profile.rs (ShaCraft mods) and mojang.rs/neoforge.rs/runtime.rs (the game itself) all 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.
    • 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 placeholder pending ShaCraft's own Azure AD app registration and Minecraft-API approval.
    • shacraft_account.rs — local ShaCraft login/registration, session and nickname claim/admission API; legacy link commands remain for compatibility.
    • admission.rs — ephemeral key generation, strict ticket response validation, canonical identity and child-only admission environment.
    • launch.rs — builds and spawns the actual java process; admission secrets must remain outside its argument substitution and JVM argfile paths.
    • updater.rs, commands/updater.rs — authenticated release metadata, bounded package download, platform installation and guarded restart.
    • deb_updater.rs — installed-package checks, one system authentication prompt and the bounded, signature-verifying non-GUI root helper.
  • src-tauri/src/settings.rs — durable local preferences; maintain backward compatibility with already-written JSON.
  • docs/manifest-v1.md — signed manifest envelope and payload contract (mods/config only).
  • docs/game-trust-boundary.md — the Mojang/NeoForge/Microsoft/Adoptium trust domains used to install and run the game itself.
  • .github/workflows/check.yml — push/PR UI checks and Linux Rust tests.
  • .github/workflows/build.yml — main-push/manual cross-platform CI artifacts; updater signing is explicitly disabled there. Local release signing and atomic feed publication are documented in docs/launcher-updates.md.

Verification

Run from repository root:

npm ci
npm test
npm run build
(cd src-tauri && /home/emil/.cargo/bin/cargo test)
npm run tauri:dev

tauri:dev is for local desktop testing. A successful web build alone does not prove Tauri commands work.

See PLAN.md for known gaps. Never label browser preview or unit tests as a successful cold game install / Microsoft OAuth / Windows/macOS beta test. The admission implementation has local unit/UI checks and unsigned Linux 0.1.2 AppImage/deb packages built on Ubuntu 26.04. Older Ubuntu compatibility has not been tested. The backend/mod rollout is active on Aeronautics as of 2026-09-10. Real isolated NeoForge admission tests and a production rejection without the mod passed; these do not certify a full production modpack join. The server has a required early duplicate-login guard so unauthenticated connections cannot evict an already-online UUID. The client mod pins the actual socket to 135.106.154.86:25567. See architecture and server rollout records.

Working conventions

  • Keep UI copy in Russian; code, identifiers and errors may remain English.
  • Prefer a small vertical slice with tests over unused abstractions.
  • Existing working-tree changes belong to the user unless this task created them. Inspect git status before staging.
  • Update this file and docs/launcher-architecture.md whenever the trust model, endpoint contract, storage layout, or release workflow changes.

Cross-platform release 0.1.5 (2026-09-10)

Published Windows x64 EXE/MSI, macOS aarch64 and x86_64 DMG/app.tar.gz, and Linux x64 AppImage/DEB on https://shacraft.ru/help#launcher. The signed stable feed includes all platforms plus the legacy/exact Linux aliases. CI source b43fc610c4, successful Actions run https://github.com/emil28092005/shacraft-launcher/actions/runs/34512683651. An initial non-Linux borrow/move compilation error in updater target selection was fixed before the final build. Native tests: Windows70, macOS74 per arch, Linux84; UI tests pass on all four runners. Local checks verify macOS bundle version/CPU type, Linux package identity and every artifact signature. Public HTTPS downloads of all eight artifacts match local SHA-256. Website418 tests plus48 subtests pass; only backend recreated, game containers unchanged. Updater signatures use the existing operator-held key, never uploaded to CI or server. Windows installers have no Authenticode signature; macOS is not Apple notarized. Native CI tests and packaging do not certify full Minecraft installs or desktop updater/restart behavior on Windows/macOS. Older unsupported clients need a manual installation of the current release. Previous releases immutable.

Admission client menu 0.1.1 (2026-09-11)

The signed Aeronautics payload now contains admission mod 0.1.1 at the existing managed path mods/shacraft-admission-0.1.0.jar to prevent duplicate mod IDs on upgrade. SHA-256: faa9ae13cb0f2d93c03dae26ab36ae20d3fb6b66c89c09254b16808d6b183f89. From the title screen (and vanilla safety acknowledgement), Multiplayer connects to fixed 135.106.154.86:25567. Cancel/errors return to TitleScreen; transitions from other screens do not auto-connect. Client-only registration, protocol 1 and one-use admission remain unchanged. Running game server was not restarted. Linux Java 21 build and 8 mod tests pass. An opt-in native live test verifies signed-manifest retrieval and download/repair/restoration of the admission jar only in a temporary directory. Mac 0.1.5 connection failure remains unclassified pending exact error/log; this is not a verified macOS fix or desktop UI test.

Minigames integration (2026-09-13, published in 0.1.6)

  • Native profile mapping is fixed: aeronautics → aoc; minigames → minigames. Both display/claim the canonical existing aoc nickname. The backend enforces the current shared aoc subscription and whitelist for Minigames as well. Ticket requests and responses remain bound to the selected server; never accept an aoc ticket as a Minigames ticket.
  • fabric.rs adds independent exact HTTPS domains meta.fabricmc.net and maven.fabricmc.net. It verifies profile identity/parent/main class, bounded metadata, portable Maven coordinates, hashes and sizes before the existing atomic library installer. Unknown loaders now fail manifest validation.
  • Minigames launches with a native-owned Quick Play endpoint 135.106.154.86:25568. The manifest cannot choose a game destination.
  • admission-client/ owns the small client-only Fabric 26.2 companion. Its configuration-phase proof uses minigames in the existing Ed25519 transcript, verifies the actual socket, canonical nickname and nonce, and signs once per process. Only a fresh launch can retry a consumed ticket. Java receives only the ephemeral ticket and private key in its child environment, never the website session/password. Keep server verification on Paper before world entry with an early duplicate UUID guard.
  • The standalone Paper admission adapter and backend remain server-project responsibilities. Do not put map/SMASH source into this launcher repository.
  • Production updater publication requires a separately built, monotonically newer launcher release and existing operator signatures. Source tests or a client jar alone do not update installed 0.1.5 launchers.

Launcher 0.1.6 was built from 799fa692 on codex/launcher-updater; divergent main remains unchanged. All four native CI builds, UI/native checks and 18 publisher signature tests pass. The unchanged Fabric companion completed a real Minecraft 26.2 → Paper configuration handshake with a synthetic account; its CI artifact is byte-identical. All eight public packages and the stable feed were signed with the existing local updater key and verified through public HTTPS downloads. See docs/release-0.1.6.md and its committed receipt. This records successful release/admission verification, not a Windows/macOS cold install or OS signing/notarization certification.

Server migration — launcher 0.1.7 (2026-09-17)

Minigames Quick Play now uses the fixed native endpoint shacraft.ru:25568. It no longer pins the retired server IP in the application binary. The Fabric admission client accepts the new actual socket IP 135.106.219.182 and retains 135.106.154.86 for the temporary forwarding path; unrelated hosts and ports remain rejected. The server published updated signed companion manifests.

The migration's full-platform packages are prepared on codex/server-migration-20260917. Existing 0.1.6 installers still connect to the old IP and need that forwarding path until upgraded. Version 0.1.7 uses a newly generated operator-held updater key and the fixed https://shacraft.ru/launcher/updates/stable-v2.json channel. It requires one manual installation. Preserve stable.json at the last old-key release; never replace it with new-key metadata. Subsequent v2-channel releases use the new key, kept only at /home/emil/.local/share/shacraft-updater/production.key. Do not claim publication based on CI packages alone.